r9234: Ensure we always change the end of the PAC, no matter what it is. Fix
[Samba/aatanasov.git] / source4 / torture / auth / pac.c
blob65bb5456cc9f4c0905c5d32a9498c7dbd0c76399
1 /*
2 Unix SMB/CIFS implementation.
4 Validate the krb5 pac generation routines
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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 2 of the License, or
11 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "system/kerberos.h"
26 #include "auth/auth.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "librpc/gen_ndr/ndr_krb5pac.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
31 static BOOL torture_pac_self_check(void)
33 NTSTATUS nt_status;
34 TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC self check");
35 DATA_BLOB tmp_blob;
36 struct PAC_DATA *pac_data;
37 struct PAC_LOGON_INFO *logon_info;
38 union netr_Validation validation;
40 /* Generate a nice, arbitary keyblock */
41 uint8_t server_bytes[16];
42 uint8_t krbtgt_bytes[16];
43 krb5_keyblock server_keyblock;
44 krb5_keyblock krbtgt_keyblock;
46 krb5_error_code ret;
48 struct smb_krb5_context *smb_krb5_context;
50 struct auth_serversupplied_info *server_info;
51 struct auth_serversupplied_info *server_info_out;
53 ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
55 if (ret) {
56 talloc_free(mem_ctx);
57 return False;
60 generate_random_buffer(server_bytes, 16);
61 generate_random_buffer(krbtgt_bytes, 16);
63 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
64 ENCTYPE_ARCFOUR_HMAC,
65 server_bytes, sizeof(server_bytes),
66 &server_keyblock);
67 if (ret) {
68 printf("Server Keyblock encoding failed: %s\n",
69 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
70 ret, mem_ctx));
72 talloc_free(mem_ctx);
73 return False;
76 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
77 ENCTYPE_ARCFOUR_HMAC,
78 krbtgt_bytes, sizeof(krbtgt_bytes),
79 &krbtgt_keyblock);
80 if (ret) {
81 printf("KRBTGT Keyblock encoding failed: %s\n",
82 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
83 ret, mem_ctx));
85 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
86 &server_keyblock);
87 talloc_free(mem_ctx);
88 return False;
91 /* We need an input, and this one requires no underlying database */
92 nt_status = auth_anonymous_server_info(mem_ctx, &server_info);
94 if (!NT_STATUS_IS_OK(nt_status)) {
95 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
96 &server_keyblock);
97 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
98 &krbtgt_keyblock);
99 talloc_free(mem_ctx);
100 return False;
103 /* OK, go ahead and make a PAC */
104 ret = kerberos_create_pac(mem_ctx, server_info,
105 smb_krb5_context->krb5_context,
106 &krbtgt_keyblock,
107 &server_keyblock,
108 &tmp_blob);
110 if (ret) {
111 printf("PAC encoding failed: %s\n",
112 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
113 ret, mem_ctx));
115 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
116 &krbtgt_keyblock);
117 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
118 &server_keyblock);
119 talloc_free(mem_ctx);
120 return False;
123 dump_data(10,tmp_blob.data,tmp_blob.length);
125 /* Now check that we can read it back */
126 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
127 tmp_blob,
128 smb_krb5_context,
129 &krbtgt_keyblock,
130 &server_keyblock);
132 if (!NT_STATUS_IS_OK(nt_status)) {
133 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
134 &krbtgt_keyblock);
135 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
136 &server_keyblock);
137 DEBUG(1, ("PAC decoding failed: %s\n",
138 nt_errstr(nt_status)));
140 talloc_free(mem_ctx);
141 return False;
144 /* Now check that we can read it back */
145 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info,
146 tmp_blob,
147 smb_krb5_context,
148 &krbtgt_keyblock,
149 &server_keyblock);
151 if (!NT_STATUS_IS_OK(nt_status)) {
152 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
153 &krbtgt_keyblock);
154 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
155 &server_keyblock);
156 printf("PAC decoding (for logon info) failed: %s\n",
157 nt_errstr(nt_status));
159 talloc_free(mem_ctx);
160 return False;
163 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
164 &krbtgt_keyblock);
165 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
166 &server_keyblock);
168 validation.sam3 = &logon_info->info3;
169 nt_status = make_server_info_netlogon_validation(mem_ctx,
171 3, &validation,
172 &server_info_out);
173 if (!NT_STATUS_IS_OK(nt_status)) {
174 printf("PAC decoding (make server info) failed: %s\n",
175 nt_errstr(nt_status));
177 talloc_free(mem_ctx);
178 return False;
181 if (!dom_sid_equal(server_info->account_sid,
182 server_info_out->account_sid)) {
183 printf("PAC Decode resulted in *different* domain SID: %s != %s\n",
184 dom_sid_string(mem_ctx, server_info->account_sid),
185 dom_sid_string(mem_ctx, server_info_out->account_sid));
186 talloc_free(mem_ctx);
187 return False;
190 talloc_free(mem_ctx);
191 return True;
195 /* This is the PAC generated on my test network, by my test Win2k3 server.
196 -- abartlet 2005-07-04
199 static const char saved_pac[] = {
200 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
201 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
202 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
203 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
204 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
205 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb,
206 0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
207 0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
208 0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
209 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00,
212 0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
213 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
215 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
220 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
221 0x41, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
226 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
227 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
228 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
229 0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
230 0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
231 0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
232 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
233 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
235 0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
236 0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
237 0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
238 0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
241 /* Check with a known 'well formed' PAC, from my test server */
242 static BOOL torture_pac_saved_check(void)
244 NTSTATUS nt_status;
245 TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC saved check");
246 DATA_BLOB tmp_blob, validate_blob;
247 struct PAC_DATA *pac_data;
248 struct PAC_LOGON_INFO *logon_info;
249 union netr_Validation validation;
251 struct auth_serversupplied_info *server_info_out;
253 krb5_keyblock server_keyblock;
254 krb5_keyblock krbtgt_keyblock;
255 uint8_t server_bytes[16];
256 struct samr_Password *krbtgt_bytes;
258 krb5_error_code ret;
260 struct smb_krb5_context *smb_krb5_context;
262 ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
264 if (ret) {
265 talloc_free(mem_ctx);
266 return False;
269 /* The krbtgt key in use when the above PAC was generated.
270 * This is an arcfour-hmac-md5 key, extracted with our 'net
271 * samdump' tool. */
272 krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, "B286757148AF7FD252C53603A150B7E7");
273 if (!krbtgt_bytes) {
274 DEBUG(0, ("Could not interpret krbtgt key"));
275 talloc_free(mem_ctx);
276 return False;
279 /* The machine trust account in use when the above PAC
280 was generated. It used arcfour-hmac-md5, so this is easy */
281 E_md4hash("iqvwmii8CuEkyY", server_bytes);
283 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
284 ENCTYPE_ARCFOUR_HMAC,
285 server_bytes, sizeof(server_bytes),
286 &server_keyblock);
287 if (ret) {
288 DEBUG(1, ("Server Keyblock encoding failed: %s\n",
289 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
290 ret, mem_ctx)));
292 talloc_free(mem_ctx);
293 return False;
296 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
297 ENCTYPE_ARCFOUR_HMAC,
298 krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
299 &krbtgt_keyblock);
300 if (ret) {
301 DEBUG(1, ("Server Keyblock encoding failed: %s\n",
302 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
303 ret, mem_ctx)));
305 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
306 &server_keyblock);
307 talloc_free(mem_ctx);
308 return False;
311 tmp_blob = data_blob(saved_pac, sizeof(saved_pac));
313 /*tmp_blob.data = file_load(lp_parm_string(-1,"torture","pac_file"), &tmp_blob.length);*/
315 dump_data(10,tmp_blob.data,tmp_blob.length);
317 /* Decode and verify the signaure on the PAC */
318 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
319 tmp_blob,
320 smb_krb5_context,
321 &krbtgt_keyblock,
322 &server_keyblock);
323 if (!NT_STATUS_IS_OK(nt_status)) {
324 DEBUG(1, ("PAC decoding failed: %s\n",
325 nt_errstr(nt_status)));
327 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
328 &krbtgt_keyblock);
329 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
330 &server_keyblock);
331 talloc_free(mem_ctx);
332 return False;
335 /* Parse the PAC again, for the logon info this time */
336 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info,
337 tmp_blob,
338 smb_krb5_context,
339 &krbtgt_keyblock,
340 &server_keyblock);
342 if (!NT_STATUS_IS_OK(nt_status)) {
343 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
344 &krbtgt_keyblock);
345 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
346 &server_keyblock);
347 printf("PAC decoding (for logon info) failed: %s\n",
348 nt_errstr(nt_status));
350 talloc_free(mem_ctx);
351 return False;
354 validation.sam3 = &logon_info->info3;
355 nt_status = make_server_info_netlogon_validation(mem_ctx,
357 3, &validation,
358 &server_info_out);
359 if (!NT_STATUS_IS_OK(nt_status)) {
360 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
361 &krbtgt_keyblock);
362 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
363 &server_keyblock);
365 printf("PAC decoding (make server info) failed: %s\n",
366 nt_errstr(nt_status));
368 talloc_free(mem_ctx);
369 return False;
372 if (!dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"),
373 server_info_out->account_sid)) {
374 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
375 &krbtgt_keyblock);
376 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
377 &server_keyblock);
379 printf("PAC Decode resulted in *different* domain SID: %s != %s\n",
380 "S-1-5-21-3048156945-3961193616-3706469200-1005",
381 dom_sid_string(mem_ctx, server_info_out->account_sid));
382 talloc_free(mem_ctx);
383 return False;
386 ret = kerberos_encode_pac(mem_ctx,
387 pac_data,
388 smb_krb5_context->krb5_context,
389 &krbtgt_keyblock,
390 &server_keyblock,
391 &validate_blob);
393 if (ret != 0) {
394 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
395 &krbtgt_keyblock);
396 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
397 &server_keyblock);
399 DEBUG(0, ("PAC push failed\n"));
400 talloc_free(mem_ctx);
401 return False;
404 dump_data(10,validate_blob.data,validate_blob.length);
406 /* compare both the length and the data bytes after a
407 * pull/push cycle. This ensures we use the exact same
408 * pointer, padding etc algorithms as win2k3.
410 if (tmp_blob.length != validate_blob.length) {
411 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
412 &krbtgt_keyblock);
413 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
414 &server_keyblock);
416 DEBUG(0, ("PAC push failed: original buffer length[%u] != created buffer length[%u]\n",
417 (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
418 talloc_free(mem_ctx);
419 return False;
422 if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
423 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
424 &krbtgt_keyblock);
425 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
426 &server_keyblock);
428 DEBUG(0, ("PAC push failed: length[%u] matches, but data does not\n",
429 (unsigned)tmp_blob.length));
430 talloc_free(mem_ctx);
431 return False;
434 /* Finally... Bugger up the signature, and check we fail the checksum */
435 tmp_blob.data[tmp_blob.length - 2]++;
437 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
438 tmp_blob,
439 smb_krb5_context,
440 &krbtgt_keyblock,
441 &server_keyblock);
442 if (NT_STATUS_IS_OK(nt_status)) {
443 DEBUG(1, ("PAC decoding DID NOT fail on broken checksum\n"));
445 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
446 &krbtgt_keyblock);
447 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
448 &server_keyblock);
449 talloc_free(mem_ctx);
450 return False;
453 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
454 &krbtgt_keyblock);
455 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
456 &server_keyblock);
458 talloc_free(mem_ctx);
459 return True;
462 BOOL torture_pac(void)
464 BOOL ret = True;
465 ret &= torture_pac_self_check();
466 ret &= torture_pac_saved_check();
467 return ret;