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 
torture_pac_self_check(struct torture_context * tctx)36 static bool torture_pac_self_check(struct torture_context *tctx)
37 {
38 	NTSTATUS nt_status;
39 	DATA_BLOB tmp_blob;
40 	struct PAC_DATA *pac_data;
41 	struct PAC_LOGON_INFO *logon_info;
42 	union netr_Validation validation;
43 
44 	/* Generate a nice, arbitary keyblock */
45 	uint8_t server_bytes[16];
46 	uint8_t krbtgt_bytes[16];
47 	krb5_keyblock server_keyblock;
48 	krb5_keyblock krbtgt_keyblock;
49 
50 	krb5_error_code ret;
51 
52 	struct smb_krb5_context *smb_krb5_context;
53 
54 	struct auth_user_info_dc *user_info_dc;
55 	struct auth_user_info_dc *user_info_dc_out;
56 
57 	krb5_principal client_principal;
58 	time_t logon_time = time(NULL);
59 
60 	TALLOC_CTX *mem_ctx = tctx;
61 
62 	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 	generate_random_buffer(server_bytes, 16);
68 	generate_random_buffer(krbtgt_bytes, 16);
69 
70 	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 	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 	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 	if (ret) {
84 		char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context,
85 						       ret, mem_ctx);
86 
87 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
88 					    &server_keyblock);
89 
90 		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 	nt_status = auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(tctx->lp_ctx), &user_info_dc);
96 
97 	if (!NT_STATUS_IS_OK(nt_status)) {
98 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
99 					    &server_keyblock);
100 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
101 					    &krbtgt_keyblock);
102 		torture_fail(tctx, "auth_anonymous_user_info_dc");
103 	}
104 
105 	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context,
106 				    user_info_dc->info->account_name,
107 				    KRB5_PRINCIPAL_PARSE_NO_REALM,
108 				    &client_principal);
109 	if (ret) {
110 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
111 					    &server_keyblock);
112 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
113 					    &krbtgt_keyblock);
114 		torture_fail(tctx, "krb5_parse_name_flags(norealm)");
115 	}
116 
117 	/* OK, go ahead and make a PAC */
118 	ret = kerberos_create_pac(mem_ctx,
119 				  user_info_dc,
120 				  smb_krb5_context->krb5_context,
121 				  &krbtgt_keyblock,
122 				  &server_keyblock,
123 				  client_principal,
124 				  logon_time,
125 				  &tmp_blob);
126 
127 	if (ret) {
128 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
129 					    &krbtgt_keyblock);
130 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
131 					    &server_keyblock);
132 		krb5_free_principal(smb_krb5_context->krb5_context,
133 				    client_principal);
134 
135 		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 	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 	nt_status = kerberos_decode_pac(mem_ctx,
145 					tmp_blob,
146 					smb_krb5_context->krb5_context,
147 					&krbtgt_keyblock,
148 					&server_keyblock,
149 					client_principal,
150 					logon_time,
151  					&pac_data);
152 
153 	if (!NT_STATUS_IS_OK(nt_status)) {
154 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
155 					    &krbtgt_keyblock);
156 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
157 					    &server_keyblock);
158 		krb5_free_principal(smb_krb5_context->krb5_context,
159 				    client_principal);
160 
161 		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 	nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
168 						     tmp_blob,
169 						     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 	if (!dom_sid_equal(user_info_dc->sids,
174 			   user_info_dc_out->sids)) {
175 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
176 					    &krbtgt_keyblock);
177 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
178 					    &server_keyblock);
179 		krb5_free_principal(smb_krb5_context->krb5_context,
180 				    client_principal);
181 
182 		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),
186 					     dom_sid_string(mem_ctx, user_info_dc_out->sids)));
187 	}
188 	talloc_free(user_info_dc_out);
189 
190 	/* Now check that we can read it back (yet again) */
191 	nt_status = kerberos_pac_logon_info(mem_ctx,
192 					    tmp_blob,
193 					    smb_krb5_context->krb5_context,
194 					    &krbtgt_keyblock,
195 					    &server_keyblock,
196 					    client_principal,
197 					    logon_time,
198 					    &logon_info);
199 
200 	if (!NT_STATUS_IS_OK(nt_status)) {
201 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
202 					    &krbtgt_keyblock);
203 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
204 					    &server_keyblock);
205 		krb5_free_principal(smb_krb5_context->krb5_context,
206 				    client_principal);
207 
208 		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 	krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
215 				    &krbtgt_keyblock);
216 	krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
217 				    &server_keyblock);
218 	krb5_free_principal(smb_krb5_context->krb5_context,
219 			    client_principal);
220 
221 	/* And make a server info from the samba-parsed PAC */
222 	validation.sam3 = &logon_info->info3;
223 	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 	if (!NT_STATUS_IS_OK(nt_status)) {
229 		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 	if (!dom_sid_equal(user_info_dc->sids,
236 			   user_info_dc_out->sids)) {
237 		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),
241 					     dom_sid_string(mem_ctx, user_info_dc_out->sids)));
242 	}
243 	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 */
torture_pac_saved_check(struct torture_context * tctx)294 static bool torture_pac_saved_check(struct torture_context *tctx)
295 {
296 	NTSTATUS nt_status;
297 	enum ndr_err_code ndr_err;
298 	DATA_BLOB tmp_blob, validate_blob;
299 	struct PAC_DATA *pac_data, pac_data2;
300 	struct PAC_LOGON_INFO *logon_info;
301 	union netr_Validation validation;
302 	const char *pac_file, *pac_kdc_key, *pac_member_key;
303 	struct auth_user_info_dc *user_info_dc_out;
304 
305 	krb5_keyblock server_keyblock;
306 	krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
307 	struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
308 
309 	krb5_error_code ret;
310 	struct smb_krb5_context *smb_krb5_context;
311 
312 	const char *principal_string;
313 	char *broken_principal_string;
314 	krb5_principal client_principal;
315 	const char *authtime_string;
316 	time_t authtime;
317 	TALLOC_CTX *mem_ctx = tctx;
318 
319 	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 	pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key",
325 					     "B286757148AF7FD252C53603A150B7E7");
326 
327 	pac_member_key = torture_setting_string(tctx, "pac_member_key",
328 						"D217FAEAE5E6B5F95CCC94077AB8A5FC");
329 
330 	torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
331 	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 	if (*pac_kdc_key == 0) {
337 		krbtgt_bytes = NULL;
338 	} else {
339 		krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
340 		if (!krbtgt_bytes) {
341 			torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
342 		}
343 	}
344 
345 	krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
346 	if (!krbsrv_bytes) {
347 		torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
348 	}
349 
350 	ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
351 				 ENCTYPE_ARCFOUR_HMAC,
352 				 krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
353 				 &server_keyblock);
354 	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 	if (krbtgt_bytes) {
361 		ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
362 					 ENCTYPE_ARCFOUR_HMAC,
363 					 krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
364 					 &krbtgt_keyblock);
365 		if (ret) {
366 			krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
367 						    &server_keyblock);
368 			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 		krbtgt_keyblock_p = &krbtgt_keyblock;
375 	} else {
376 		krbtgt_keyblock_p = NULL;
377 	}
378 
379 	pac_file = torture_setting_string(tctx, "pac_file", NULL);
380 	if (pac_file) {
381 		tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
382 		torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
383 	} else {
384 		tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
385 	}
386 
387 	dump_data(10,tmp_blob.data,tmp_blob.length);
388 
389 	principal_string = torture_setting_string(tctx, "pac_client_principal",
390 						  "w2003final$@WIN2K3.THINKER.LOCAL");
391 
392 	authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
393 	authtime = strtoull(authtime_string, NULL, 0);
394 
395 	ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string,
396 			      &client_principal);
397 	if (ret) {
398 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
399 					    krbtgt_keyblock_p);
400 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
401 					    &server_keyblock);
402 		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 	nt_status = kerberos_decode_pac(mem_ctx,
411 					tmp_blob,
412 					smb_krb5_context->krb5_context,
413 					krbtgt_keyblock_p,
414 					&server_keyblock,
415 					client_principal, authtime, &pac_data);
416 	if (!NT_STATUS_IS_OK(nt_status)) {
417 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
418 					    krbtgt_keyblock_p);
419 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
420 					    &server_keyblock);
421 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
422 
423 		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 	nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
430 						     tmp_blob,
431 						     smb_krb5_context->krb5_context,
432 						      &user_info_dc_out,
433 						      NULL, NULL);
434 
435 	if (!NT_STATUS_IS_OK(nt_status)) {
436 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
437 					    krbtgt_keyblock_p);
438 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
439 					    &server_keyblock);
440 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
441 
442 		torture_fail(tctx, talloc_asprintf(tctx,
443 						   "(saved test) Heimdal PAC decoding failed: %s",
444 						   nt_errstr(nt_status)));
445 	}
446 
447 	if (!pac_file &&
448 	    !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
449 						"S-1-5-21-3048156945-3961193616-3706469200-1005"),
450 			   user_info_dc_out->sids)) {
451 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
452 					    krbtgt_keyblock_p);
453 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
454 					    &server_keyblock);
455 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
456 
457 		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)));
462 	}
463 
464 	talloc_free(user_info_dc_out);
465 
466 	/* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
467 	nt_status = kerberos_pac_logon_info(mem_ctx,
468 					    tmp_blob,
469 					    smb_krb5_context->krb5_context,
470 					    krbtgt_keyblock_p,
471 					    &server_keyblock,
472 					    client_principal, authtime, &logon_info);
473 
474 	if (!NT_STATUS_IS_OK(nt_status)) {
475 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
476 					    krbtgt_keyblock_p);
477 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
478 					    &server_keyblock);
479 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
480 
481 		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 	validation.sam3 = &logon_info->info3;
488 	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 	if (!NT_STATUS_IS_OK(nt_status)) {
494 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
495 					    krbtgt_keyblock_p);
496 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
497 					    &server_keyblock);
498 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
499 
500 		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 	if (!pac_file &&
507 	    !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
508 						"S-1-5-21-3048156945-3961193616-3706469200-1005"),
509 			   user_info_dc_out->sids)) {
510 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
511 					    krbtgt_keyblock_p);
512 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
513 					    &server_keyblock);
514 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
515 
516 		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)));
521 	}
522 
523 	if (krbtgt_bytes == NULL) {
524 		torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
525 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
526 					    &server_keyblock);
527 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
528 		return true;
529 	}
530 
531 	ret = kerberos_encode_pac(mem_ctx,
532 				  pac_data,
533 				  smb_krb5_context->krb5_context,
534 				  krbtgt_keyblock_p,
535 				  &server_keyblock,
536 				  &validate_blob);
537 
538 	if (ret != 0) {
539 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
540 					    krbtgt_keyblock_p);
541 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
542 					    &server_keyblock);
543 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
544 
545 		torture_fail(tctx, "(saved test) PAC push failed");
546 	}
547 
548 	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 	if (tmp_blob.length != validate_blob.length) {
555 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
556 					    krbtgt_keyblock_p);
557 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
558 					    &server_keyblock);
559 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
560 
561 		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 	if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
568 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
569 					    krbtgt_keyblock_p);
570 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
571 					    &server_keyblock);
572 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
573 
574 		DEBUG(0, ("tmp_data:\n"));
575 		dump_data(0, tmp_blob.data, tmp_blob.length);
576 		DEBUG(0, ("validate_blob:\n"));
577 		dump_data(0, validate_blob.data, validate_blob.length);
578 
579 		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 	ret = kerberos_create_pac(mem_ctx,
583 				  user_info_dc_out,
584 				  smb_krb5_context->krb5_context,
585 				  krbtgt_keyblock_p,
586 				  &server_keyblock,
587 				  client_principal, authtime,
588 				  &validate_blob);
589 
590 	if (ret != 0) {
591 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
592 					    krbtgt_keyblock_p);
593 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
594 					    &server_keyblock);
595 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
596 
597 		torture_fail(tctx, "(saved test) regnerated PAC create failed");
598 	}
599 
600 	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 	if (tmp_blob.length != validate_blob.length) {
607 		ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
608 					       &pac_data2,
609 					       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
610 		nt_status = ndr_map_error2ntstatus(ndr_err);
611 		torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
612 
613 		NDR_PRINT_DEBUG(PAC_DATA, pac_data);
614 
615 		NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
616 
617 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
618 					    krbtgt_keyblock_p);
619 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
620 					    &server_keyblock);
621 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
622 
623 		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 	if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
629 		ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
630 					       &pac_data2,
631 					       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
632 		nt_status = ndr_map_error2ntstatus(ndr_err);
633 		torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
634 
635 		NDR_PRINT_DEBUG(PAC_DATA, pac_data);
636 
637 		NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
638 
639 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
640 					    krbtgt_keyblock_p);
641 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
642 					    &server_keyblock);
643 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
644 
645 		DEBUG(0, ("tmp_data:\n"));
646 		dump_data(0, tmp_blob.data, tmp_blob.length);
647 		DEBUG(0, ("validate_blob:\n"));
648 		dump_data(0, validate_blob.data, validate_blob.length);
649 
650 		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 	nt_status = kerberos_decode_pac(mem_ctx,
656 					tmp_blob,
657 					smb_krb5_context->krb5_context,
658 					krbtgt_keyblock_p,
659 					&server_keyblock,
660 					client_principal,
661 					authtime + 1, &pac_data);
662 	if (NT_STATUS_IS_OK(nt_status)) {
663 
664 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
665 					    krbtgt_keyblock_p);
666 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
667 					    &server_keyblock);
668 		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
669 		torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
670 	}
671 
672 	/* Break the client principal */
673 	krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
674 
675 	broken_principal_string = talloc_strdup(mem_ctx, principal_string);
676 	broken_principal_string[0]++;
677 
678 	ret = krb5_parse_name(smb_krb5_context->krb5_context,
679 			      broken_principal_string, &client_principal);
680 	if (ret) {
681 
682 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
683 					    krbtgt_keyblock_p);
684 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
685 					    &server_keyblock);
686 		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 	nt_status = kerberos_decode_pac(mem_ctx,
692 					tmp_blob,
693 					smb_krb5_context->krb5_context,
694 					krbtgt_keyblock_p,
695 					&server_keyblock,
696 					client_principal,
697 					authtime, &pac_data);
698 	if (NT_STATUS_IS_OK(nt_status)) {
699 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
700 					    krbtgt_keyblock_p);
701 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
702 					    &server_keyblock);
703 		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 	tmp_blob.data[tmp_blob.length - 2]++;
708 
709 	nt_status = kerberos_decode_pac(mem_ctx,
710 					tmp_blob,
711 					smb_krb5_context->krb5_context,
712 					krbtgt_keyblock_p,
713 					&server_keyblock,
714 					client_principal,
715 					authtime,
716 					&pac_data);
717 	if (NT_STATUS_IS_OK(nt_status)) {
718 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
719 					    krbtgt_keyblock_p);
720 		krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
721 					    &server_keyblock);
722 		torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
723 	}
724 
725 	krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
726 				    krbtgt_keyblock_p);
727 	krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
728 				    &server_keyblock);
729 	return true;
730 }
731 
torture_pac(TALLOC_CTX * mem_ctx)732 struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
733 {
734 	struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
735 
736 	torture_suite_add_simple_test(suite, "self check",
737 				      torture_pac_self_check);
738 	torture_suite_add_simple_test(suite, "saved check",
739 				      torture_pac_saved_check);
740 	return suite;
741 }
742