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.
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)
34 TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC self check");
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;
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);
60 generate_random_buffer(server_bytes, 16);
61 generate_random_buffer(krbtgt_bytes, 16);
63 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
65 server_bytes, sizeof(server_bytes),
68 printf("Server Keyblock encoding failed: %s\n",
69 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
76 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
78 krbtgt_bytes, sizeof(krbtgt_bytes),
81 printf("KRBTGT Keyblock encoding failed: %s\n",
82 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
85 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
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,
97 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
103 /* OK, go ahead and make a PAC */
104 ret = kerberos_create_pac(mem_ctx, server_info,
105 smb_krb5_context->krb5_context,
112 printf("PAC encoding failed: %s\n",
113 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
116 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
118 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
120 talloc_free(mem_ctx);
124 dump_data(10,tmp_blob.data,tmp_blob.length);
126 /* Now check that we can read it back */
127 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
129 smb_krb5_context->krb5_context,
133 if (!NT_STATUS_IS_OK(nt_status)) {
134 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
136 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
138 DEBUG(1, ("PAC decoding failed: %s\n",
139 nt_errstr(nt_status)));
141 talloc_free(mem_ctx);
145 /* Now check that we can read it back */
146 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info,
148 smb_krb5_context->krb5_context,
152 if (!NT_STATUS_IS_OK(nt_status)) {
153 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
155 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
157 printf("PAC decoding (for logon info) failed: %s\n",
158 nt_errstr(nt_status));
160 talloc_free(mem_ctx);
164 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
166 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
169 validation.sam3 = &logon_info->info3;
170 nt_status = make_server_info_netlogon_validation(mem_ctx,
174 if (!NT_STATUS_IS_OK(nt_status)) {
175 printf("PAC decoding (make server info) failed: %s\n",
176 nt_errstr(nt_status));
178 talloc_free(mem_ctx);
182 if (!dom_sid_equal(server_info->account_sid,
183 server_info_out->account_sid)) {
184 printf("PAC Decode resulted in *different* domain SID: %s != %s\n",
185 dom_sid_string(mem_ctx, server_info->account_sid),
186 dom_sid_string(mem_ctx, server_info_out->account_sid));
187 talloc_free(mem_ctx);
191 talloc_free(mem_ctx);
196 /* This is the PAC generated on my test network, by my test Win2k3 server.
197 -- abartlet 2005-07-04
200 static const uint8_t saved_pac[] = {
201 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
202 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
203 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
204 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
205 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
206 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb,
207 0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
208 0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
209 0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
210 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00,
213 0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
214 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
216 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
221 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
222 0x41, 0x00, 0x4c, 0x00, 0x24, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
227 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
228 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
229 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
230 0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
231 0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
232 0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
233 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
234 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
236 0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
237 0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
238 0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
239 0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
242 /* Check with a known 'well formed' PAC, from my test server */
243 static BOOL torture_pac_saved_check(void)
246 TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC saved check");
247 DATA_BLOB tmp_blob, validate_blob;
248 struct PAC_DATA *pac_data;
249 struct PAC_LOGON_INFO *logon_info;
250 union netr_Validation validation;
251 const char *pac_file, *pac_kdc_key, *pac_member_key;
253 struct auth_serversupplied_info *server_info_out;
255 krb5_keyblock server_keyblock;
256 krb5_keyblock krbtgt_keyblock;
257 struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
261 struct smb_krb5_context *smb_krb5_context;
263 ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
266 talloc_free(mem_ctx);
270 pac_kdc_key = lp_parm_string(-1,"torture","pac_kdc_key");
271 if (pac_kdc_key == NULL) {
272 pac_kdc_key = "B286757148AF7FD252C53603A150B7E7";
275 pac_member_key = lp_parm_string(-1,"torture","pac_member_key");
276 if (pac_member_key == NULL) {
277 pac_member_key = "D217FAEAE5E6B5F95CCC94077AB8A5FC";
280 printf("Using pac_kdc_key '%s'\n", pac_kdc_key);
281 printf("Using pac_member_key '%s'\n", pac_member_key);
283 /* The krbtgt key in use when the above PAC was generated.
284 * This is an arcfour-hmac-md5 key, extracted with our 'net
286 krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
288 DEBUG(0, ("Could not interpret krbtgt key"));
289 talloc_free(mem_ctx);
293 krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
295 DEBUG(0, ("Could not interpret krbsrv key"));
296 talloc_free(mem_ctx);
300 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
301 ENCTYPE_ARCFOUR_HMAC,
302 krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
305 DEBUG(1, ("Server Keyblock encoding failed: %s\n",
306 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
309 talloc_free(mem_ctx);
313 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
314 ENCTYPE_ARCFOUR_HMAC,
315 krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
318 DEBUG(1, ("Server Keyblock encoding failed: %s\n",
319 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
322 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
324 talloc_free(mem_ctx);
328 pac_file = lp_parm_string(-1,"torture","pac_file");
330 tmp_blob.data = file_load(pac_file, &tmp_blob.length, mem_ctx);
331 printf("Loaded pac of size %d from %s\n", tmp_blob.length, pac_file);
333 tmp_blob = data_blob(saved_pac, sizeof(saved_pac));
334 file_save("x.dat", tmp_blob.data, tmp_blob.length);
337 dump_data(10,tmp_blob.data,tmp_blob.length);
339 /* Decode and verify the signaure on the PAC */
340 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
345 if (!NT_STATUS_IS_OK(nt_status)) {
346 DEBUG(1, ("PAC decoding failed: %s\n",
347 nt_errstr(nt_status)));
349 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
351 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
353 talloc_free(mem_ctx);
357 /* Parse the PAC again, for the logon info this time */
358 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info,
364 if (!NT_STATUS_IS_OK(nt_status)) {
365 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
367 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
369 printf("PAC decoding (for logon info) failed: %s\n",
370 nt_errstr(nt_status));
372 talloc_free(mem_ctx);
376 validation.sam3 = &logon_info->info3;
377 nt_status = make_server_info_netlogon_validation(mem_ctx,
381 if (!NT_STATUS_IS_OK(nt_status)) {
382 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
384 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
387 printf("PAC decoding (make server info) failed: %s\n",
388 nt_errstr(nt_status));
390 talloc_free(mem_ctx);
395 !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"),
396 server_info_out->account_sid)) {
397 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
399 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
402 printf("PAC Decode resulted in *different* domain SID: %s != %s\n",
403 "S-1-5-21-3048156945-3961193616-3706469200-1005",
404 dom_sid_string(mem_ctx, server_info_out->account_sid));
405 talloc_free(mem_ctx);
409 ret = kerberos_encode_pac(mem_ctx,
411 smb_krb5_context->krb5_context,
417 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
419 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
422 DEBUG(0, ("PAC push failed\n"));
423 talloc_free(mem_ctx);
427 dump_data(10,validate_blob.data,validate_blob.length);
429 /* compare both the length and the data bytes after a
430 * pull/push cycle. This ensures we use the exact same
431 * pointer, padding etc algorithms as win2k3.
433 if (tmp_blob.length != validate_blob.length) {
434 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
436 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
439 DEBUG(0, ("PAC push failed: original buffer length[%u] != created buffer length[%u]\n",
440 (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
441 talloc_free(mem_ctx);
445 if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
446 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
448 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
451 DEBUG(0, ("PAC push failed: length[%u] matches, but data does not\n",
452 (unsigned)tmp_blob.length));
453 talloc_free(mem_ctx);
457 /* Finally... Bugger up the signature, and check we fail the checksum */
458 tmp_blob.data[tmp_blob.length - 2]++;
460 nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
465 if (NT_STATUS_IS_OK(nt_status)) {
466 DEBUG(1, ("PAC decoding DID NOT fail on broken checksum\n"));
468 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
470 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
472 talloc_free(mem_ctx);
476 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
478 krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
481 talloc_free(mem_ctx);
485 BOOL torture_pac(void)
488 ret &= torture_pac_self_check();
489 ret &= torture_pac_saved_check();