2 Unix SMB/CIFS implementation.
4 Validate the krb5 pac generation routines
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
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.
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, see <http://www.gnu.org/licenses/>.
24 #include "system/kerberos.h"
25 #include "torture/smbtorture.h"
26 #include "torture/winbind/proto.h"
27 #include "torture/krb5/proto.h"
28 #include "auth/credentials/credentials.h"
29 #include "lib/cmdline/cmdline.h"
30 #include "source4/auth/kerberos/kerberos.h"
31 #include "source4/auth/kerberos/kerberos_util.h"
32 #include "lib/util/util_net.h"
34 #define krb5_is_app_tag(dat,tag) \
35 ((dat != NULL) && (dat)->length && \
36 (((((char *)(dat)->data)[0] & ~0x20) == ((tag) | 0x40))))
38 #define krb5_is_krb_error(dat) krb5_is_app_tag(dat, 30)
40 enum torture_krb5_test {
41 TORTURE_KRB5_TEST_PLAIN,
42 TORTURE_KRB5_TEST_PAC_REQUEST,
43 TORTURE_KRB5_TEST_BREAK_PW,
44 TORTURE_KRB5_TEST_CLOCK_SKEW,
45 TORTURE_KRB5_TEST_AES,
46 TORTURE_KRB5_TEST_RC4,
47 TORTURE_KRB5_TEST_AES_RC4,
50 * This is in and out of the client.
51 * Out refers to requests, in refers to replies
53 TORTURE_KRB5_TEST_CHANGE_SERVER_OUT,
54 TORTURE_KRB5_TEST_CHANGE_SERVER_IN,
55 TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH,
58 struct torture_krb5_context {
59 struct torture_context *tctx;
60 struct addrinfo *server;
61 enum torture_krb5_test test;
65 const char *krb5_service;
66 const char *krb5_hostname;
70 * Confirm that the outgoing packet meets certain expectations. This
71 * should be extended to further assert the correct and expected
72 * behaviour of the krb5 libs, so we know what we are sending to the
77 static bool torture_krb5_pre_send_test(struct torture_krb5_context *test_context, krb5_data *send_buf)
80 switch (test_context->test)
82 case TORTURE_KRB5_TEST_PLAIN:
83 case TORTURE_KRB5_TEST_PAC_REQUEST:
84 case TORTURE_KRB5_TEST_BREAK_PW:
85 case TORTURE_KRB5_TEST_CLOCK_SKEW:
86 case TORTURE_KRB5_TEST_AES:
87 case TORTURE_KRB5_TEST_RC4:
88 case TORTURE_KRB5_TEST_AES_RC4:
89 case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
90 torture_assert_int_equal(test_context->tctx,
91 decode_AS_REQ(send_buf->data, send_buf->length, &test_context->as_req, &used), 0,
92 "decode_AS_REQ failed");
93 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
94 torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno, 5, "Got wrong as_req->pvno");
96 case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
97 case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
100 krb5_error_code k5ret;
101 krb5_data modified_send_buf;
102 torture_assert_int_equal(test_context->tctx,
103 decode_AS_REQ(send_buf->data, send_buf->length, &test_context->as_req, &used), 0,
104 "decode_AS_REQ failed");
105 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
106 torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno, 5, "Got wrong as_req->pvno");
108 /* Only change it if configured with --option=torture:krb5-hostname= */
109 if (test_context->krb5_hostname[0] == '\0') {
113 mod_as_req = test_context->as_req;
115 torture_assert_int_equal(test_context->tctx,
116 mod_as_req.req_body.sname->name_string.len, 2,
117 "Sending wrong mod_as_req.req_body->sname.name_string.len");
118 free(mod_as_req.req_body.sname->name_string.val[0]);
119 free(mod_as_req.req_body.sname->name_string.val[1]);
120 mod_as_req.req_body.sname->name_string.val[0] = strdup(test_context->krb5_service);
121 mod_as_req.req_body.sname->name_string.val[1] = strdup(test_context->krb5_hostname);
123 ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf.data, modified_send_buf.length,
124 &mod_as_req, &used, k5ret);
125 torture_assert_int_equal(test_context->tctx,
127 "encode_AS_REQ failed");
129 *send_buf = modified_send_buf;
136 static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
137 const krb5_data *reply,
138 krb5_error_code expected_error,
141 KRB_ERROR error = { 0 };
145 rc = decode_KRB_ERROR(reply->data, reply->length, &error, &used);
146 torture_assert_int_equal(test_context->tctx,
148 "decode_KRB_ERROR failed");
150 torture_assert_int_equal(test_context->tctx,
153 torture_assert_int_equal(test_context->tctx,
155 "Got wrong error.pvno");
156 torture_assert_int_equal(test_context->tctx,
157 error.error_code, expected_error - KRB5KDC_ERR_NONE,
158 "Got wrong error.error_code");
164 bool found_enc_ts = false;
165 bool found_etype_info2 = false;
166 torture_assert(test_context->tctx,
167 error.e_data != NULL,
168 "No e-data returned");
170 rc = decode_METHOD_DATA(error.e_data->data,
171 error.e_data->length,
174 torture_assert_int_equal(test_context->tctx,
176 "Got invalid method data");
178 torture_assert(test_context->tctx,
181 for (i = 0; i < m.len; i++) {
182 if (m.val[i].padata_type == KRB5_PADATA_ENC_TIMESTAMP) {
185 else if (m.val[i].padata_type == KRB5_PADATA_ETYPE_INFO2) {
186 found_etype_info2 = true;
189 torture_assert(test_context->tctx,
191 "PADATA_ETYPE_INFO2 not found");
192 if (expected_error != KRB5KDC_ERR_PREAUTH_FAILED)
193 torture_assert(test_context->tctx,
195 "Encrypted timestamp not found");
198 free_KRB_ERROR(&error);
203 static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
204 const krb5_data *reply,
205 const krb5_enctype* allowed_enctypes)
207 ENCTYPE reply_enctype = { 0 };
210 int expected_enctype = ETYPE_NULL;
212 rc = decode_AS_REP(reply->data,
214 &test_context->as_rep,
216 torture_assert_int_equal(test_context->tctx,
218 "decode_AS_REP failed");
219 torture_assert_int_equal(test_context->tctx,
222 torture_assert_int_equal(test_context->tctx,
223 test_context->as_rep.pvno, 5,
224 "Got wrong as_rep->pvno");
225 torture_assert_int_equal(test_context->tctx,
226 test_context->as_rep.ticket.tkt_vno, 5,
227 "Got wrong as_rep->ticket.tkt_vno");
228 torture_assert(test_context->tctx,
229 test_context->as_rep.ticket.enc_part.kvno,
230 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
232 if (test_context->as_req.padata) {
234 * If the AS-REQ contains a PA-ENC-TIMESTAMP, then
235 * that encryption type is used to determine the reply
239 const PA_DATA *pa = krb5_find_padata(test_context->as_req.padata->val,
240 test_context->as_req.padata->len,
241 KRB5_PADATA_ENC_TIMESTAMP,
246 krb5_error_code ret = decode_EncryptedData(pa->padata_value.data,
247 pa->padata_value.length,
249 torture_assert_int_equal(test_context->tctx,
252 "decode_EncryptedData failed");
253 expected_enctype = ed.etype;
254 free_EncryptedData(&ed);
257 if (expected_enctype == ETYPE_NULL) {
259 * Otherwise, find the strongest enctype contained in
260 * the AS-REQ supported enctypes list.
262 const krb5_enctype *p = NULL;
264 for (p = krb5_kerberos_enctypes(NULL); *p != (krb5_enctype)ETYPE_NULL; ++p) {
267 if ((*p == (krb5_enctype)ETYPE_AES256_CTS_HMAC_SHA1_96 ||
268 *p == (krb5_enctype)ETYPE_AES128_CTS_HMAC_SHA1_96) &&
269 !test_context->as_req.req_body.kdc_options.canonicalize)
272 * AES encryption types are only used here when
273 * we set the canonicalize flag, as the salt
279 for (j = 0; j < test_context->as_req.req_body.etype.len; ++j) {
280 krb5_enctype etype = test_context->as_req.req_body.etype.val[j];
282 expected_enctype = etype;
287 if (expected_enctype != (krb5_enctype)ETYPE_NULL) {
294 /* Ensure the enctype to check against is an expected type. */
295 const krb5_enctype *p = NULL;
297 for (p = allowed_enctypes; *p != (krb5_enctype)ETYPE_NULL; ++p) {
298 if (*p == expected_enctype) {
304 torture_assert(test_context->tctx,
306 "Calculated enctype not in allowed list");
309 reply_enctype = test_context->as_rep.enc_part.etype;
310 torture_assert_int_equal(test_context->tctx,
311 reply_enctype, expected_enctype,
312 "Ticket encrypted with invalid algorithm");
318 * Confirm that the incoming packet from the KDC meets certain
319 * expectations. This uses a switch and the packet count to work out
320 * what test we are in, and where in the test we are, so we can assert
321 * on the expected reply packets from the KDC.
325 static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_context, krb5_data *recv_buf)
331 switch (test_context->test)
333 case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
334 case TORTURE_KRB5_TEST_PLAIN:
335 if (test_context->packet_count == 0) {
336 ok = torture_check_krb5_error(test_context,
338 KRB5KDC_ERR_PREAUTH_REQUIRED,
340 torture_assert(test_context->tctx,
342 "torture_check_krb5_error failed");
343 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
344 && (test_context->packet_count == 1)) {
345 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
346 torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
347 torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
348 "Got wrong error.error_code");
349 free_KRB_ERROR(&error);
351 torture_assert_int_equal(test_context->tctx,
352 decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
353 "decode_AS_REP failed");
354 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
355 torture_assert_int_equal(test_context->tctx,
356 test_context->as_rep.pvno, 5,
357 "Got wrong as_rep->pvno");
358 torture_assert_int_equal(test_context->tctx,
359 test_context->as_rep.ticket.tkt_vno, 5,
360 "Got wrong as_rep->ticket.tkt_vno");
361 torture_assert(test_context->tctx,
362 test_context->as_rep.ticket.enc_part.kvno,
363 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
364 if (test_context->test == TORTURE_KRB5_TEST_PLAIN) {
365 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
366 torture_assert_int_not_equal(test_context->tctx,
367 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
368 0, "Did not get a RODC number in the KVNO");
370 torture_assert_int_equal(test_context->tctx,
371 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
372 0, "Unexpecedly got a RODC number in the KVNO");
375 free_AS_REP(&test_context->as_rep);
377 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
378 free_AS_REQ(&test_context->as_req);
382 * Confirm correct error codes when we ask for the PAC. This behaviour is rather odd...
384 case TORTURE_KRB5_TEST_PAC_REQUEST:
385 if (test_context->packet_count == 0) {
386 ok = torture_check_krb5_error(test_context,
388 KRB5KDC_ERR_PREAUTH_REQUIRED,
390 torture_assert(test_context->tctx,
392 "torture_check_krb5_error failed");
393 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
394 && (test_context->packet_count == 1)) {
395 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
396 torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
397 torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
398 "Got wrong error.error_code");
399 free_KRB_ERROR(&error);
401 torture_assert_int_equal(test_context->tctx,
402 decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
403 "decode_AS_REP failed");
404 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
405 torture_assert_int_equal(test_context->tctx, test_context->as_rep.pvno, 5, "Got wrong as_rep->pvno");
406 free_AS_REP(&test_context->as_rep);
408 torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
409 free_AS_REQ(&test_context->as_req);
413 * Confirm correct error codes when we deliberately send the wrong password
415 case TORTURE_KRB5_TEST_BREAK_PW:
416 if (test_context->packet_count == 0) {
417 ok = torture_check_krb5_error(test_context,
419 KRB5KDC_ERR_PREAUTH_REQUIRED,
421 torture_assert(test_context->tctx,
423 "torture_check_krb5_error failed");
424 } else if (test_context->packet_count == 1) {
425 ok = torture_check_krb5_error(test_context,
427 KRB5KDC_ERR_PREAUTH_FAILED,
429 torture_assert(test_context->tctx,
431 "torture_check_krb5_error failed");
433 torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
434 free_AS_REQ(&test_context->as_req);
438 * Confirm correct error codes when we deliberately skew the client clock
440 case TORTURE_KRB5_TEST_CLOCK_SKEW:
441 if (test_context->packet_count == 0) {
442 ok = torture_check_krb5_error(test_context,
444 KRB5KDC_ERR_PREAUTH_REQUIRED,
446 torture_assert(test_context->tctx,
448 "torture_check_krb5_error failed");
449 } else if (test_context->packet_count == 1) {
450 ok = torture_check_krb5_error(test_context,
454 torture_assert(test_context->tctx,
456 "torture_check_krb5_error failed");
458 torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
459 free_AS_REQ(&test_context->as_req);
461 case TORTURE_KRB5_TEST_AES:
462 torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES\n");
464 if (test_context->packet_count == 0) {
465 ok = torture_check_krb5_error(test_context,
467 KRB5KDC_ERR_PREAUTH_REQUIRED,
469 torture_assert(test_context->tctx,
471 "torture_check_krb5_error failed");
472 } else if (krb5_is_krb_error(recv_buf)) {
473 ok = torture_check_krb5_error(test_context,
475 KRB5KRB_ERR_RESPONSE_TOO_BIG,
477 torture_assert(test_context->tctx,
479 "torture_check_krb5_error failed");
481 const krb5_enctype allowed_enctypes[] = {
482 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
485 ok = torture_check_krb5_as_rep_enctype(test_context,
488 torture_assert(test_context->tctx,
490 "torture_check_krb5_as_rep_enctype failed");
493 torture_assert(test_context->tctx,
494 test_context->packet_count < 3,
497 case TORTURE_KRB5_TEST_RC4:
498 torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_RC4\n");
500 if (test_context->packet_count == 0) {
501 ok = torture_check_krb5_error(test_context,
503 KRB5KDC_ERR_PREAUTH_REQUIRED,
505 torture_assert(test_context->tctx,
507 "torture_check_krb5_error failed");
508 } else if (krb5_is_krb_error(recv_buf)) {
509 ok = torture_check_krb5_error(test_context,
511 KRB5KRB_ERR_RESPONSE_TOO_BIG,
513 torture_assert(test_context->tctx,
515 "torture_check_krb5_error failed");
517 const krb5_enctype allowed_enctypes[] = {
518 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
521 ok = torture_check_krb5_as_rep_enctype(test_context,
524 torture_assert(test_context->tctx,
526 "torture_check_krb5_as_rep_enctype failed");
529 torture_assert(test_context->tctx,
530 test_context->packet_count < 3,
533 case TORTURE_KRB5_TEST_AES_RC4:
534 torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES_RC4\n");
536 if (test_context->packet_count == 0) {
537 ok = torture_check_krb5_error(test_context,
539 KRB5KDC_ERR_PREAUTH_REQUIRED,
541 torture_assert(test_context->tctx,
543 "torture_check_krb5_error failed");
544 } else if (krb5_is_krb_error(recv_buf)) {
545 ok = torture_check_krb5_error(test_context,
547 KRB5KRB_ERR_RESPONSE_TOO_BIG,
549 torture_assert(test_context->tctx,
551 "torture_check_krb5_error failed");
553 const krb5_enctype allowed_enctypes[] = {
554 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
555 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
558 ok = torture_check_krb5_as_rep_enctype(test_context,
561 torture_assert(test_context->tctx,
563 "torture_check_krb5_as_rep_enctype failed");
566 torture_assert(test_context->tctx,
567 test_context->packet_count < 3,
570 case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
571 case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
574 krb5_error_code k5ret;
575 krb5_data modified_recv_buf;
576 if (test_context->packet_count == 0) {
577 ok = torture_check_krb5_error(test_context,
579 KRB5KDC_ERR_PREAUTH_REQUIRED,
581 torture_assert(test_context->tctx,
583 "torture_check_krb5_error failed");
584 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
585 && (test_context->packet_count == 1)) {
586 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
587 torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
588 torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
589 "Got wrong error.error_code");
590 free_KRB_ERROR(&error);
592 torture_assert_int_equal(test_context->tctx,
593 decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
594 "decode_AS_REP failed");
595 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
596 torture_assert_int_equal(test_context->tctx,
597 test_context->as_rep.pvno, 5,
598 "Got wrong as_rep->pvno");
599 torture_assert_int_equal(test_context->tctx,
600 test_context->as_rep.ticket.tkt_vno, 5,
601 "Got wrong as_rep->ticket.tkt_vno");
602 torture_assert_int_equal(test_context->tctx,
603 test_context->as_rep.ticket.sname.name_string.len, 2,
604 "Got wrong as_rep->ticket.sname.name_string.len");
605 free(test_context->as_rep.ticket.sname.name_string.val[0]);
606 free(test_context->as_rep.ticket.sname.name_string.val[1]);
607 test_context->as_rep.ticket.sname.name_string.val[0] = strdup("bad");
608 test_context->as_rep.ticket.sname.name_string.val[1] = strdup("mallory");
610 mod_as_rep = test_context->as_rep;
612 ASN1_MALLOC_ENCODE(AS_REP, modified_recv_buf.data, modified_recv_buf.length,
613 &mod_as_rep, &used, k5ret);
614 torture_assert_int_equal(test_context->tctx,
616 "encode_AS_REQ failed");
617 krb5_data_free(recv_buf);
619 *recv_buf = modified_recv_buf;
620 free_AS_REQ(&test_context->as_req);
622 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
634 * This function is set in torture_krb5_init_context as krb5
635 * send_and_recv function. This allows us to override what server the
636 * test is aimed at, and to inspect the packets just before they are
637 * sent to the network, and before they are processed on the recv
640 * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
641 * functions are implement the actual tests.
643 * When this asserts, the caller will get a spurious 'cannot contact
647 static krb5_error_code test_krb5_send_to_realm_override(
648 struct smb_krb5_context *smb_krb5_context,
649 void *data, /* struct torture_krb5_context */
650 krb5_const_realm realm,
652 const krb5_data *send_buf,
655 krb5_error_code k5ret;
657 krb5_data modified_send_buf = *send_buf;
659 struct torture_krb5_context *test_context
660 = talloc_get_type_abort(data, struct torture_krb5_context);
662 ok = torture_krb5_pre_send_test(test_context, &modified_send_buf);
667 k5ret = smb_krb5_send_and_recv_func_forced_tcp(smb_krb5_context,
668 test_context->server,
675 ok = torture_krb5_post_recv_test(test_context, recv_buf);
680 test_context->packet_count++;
685 static int test_context_destructor(struct torture_krb5_context *test_context)
687 freeaddrinfo(test_context->server);
692 static bool torture_krb5_init_context(struct torture_context *tctx,
693 enum torture_krb5_test test,
694 struct smb_krb5_context **smb_krb5_context)
696 const char *host = torture_setting_string(tctx, "host", NULL);
697 krb5_error_code k5ret;
700 struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
701 torture_assert(tctx, test_context != NULL, "Failed to allocate");
703 test_context->test = test;
704 test_context->tctx = tctx;
706 test_context->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
707 test_context->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
709 k5ret = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context);
710 torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
712 ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
713 torture_assert(tctx, ok, "Failed to parse target server");
715 talloc_set_destructor(test_context, test_context_destructor);
717 set_sockaddr_port(test_context->server->ai_addr, 88);
719 k5ret = smb_krb5_set_send_to_kdc_func((*smb_krb5_context),
720 test_krb5_send_to_realm_override,
721 NULL, /* send_to_kdc */
723 torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
727 static bool torture_krb5_as_req_creds(struct torture_context *tctx,
728 struct cli_credentials *credentials,
729 enum torture_krb5_test test)
731 krb5_error_code k5ret;
734 krb5_principal principal;
735 struct smb_krb5_context *smb_krb5_context;
736 krb5_context k5_context;
737 enum credentials_obtained obtained;
738 const char *error_string;
739 const char *password = cli_credentials_get_password(credentials);
740 const char *expected_principal_string;
741 krb5_get_init_creds_opt *krb_options = NULL;
743 const char *krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
746 ok = torture_krb5_init_context(tctx, test, &smb_krb5_context);
747 torture_assert(tctx, ok, "torture_krb5_init_context failed");
748 k5_context = smb_krb5_context->krb5_context;
750 expected_principal_string
751 = cli_credentials_get_principal(credentials,
754 realm = strupper_talloc(tctx, cli_credentials_get_realm(credentials));
755 k5ret = principal_from_credentials(tctx, credentials, smb_krb5_context,
756 &principal, &obtained, &error_string);
757 torture_assert_int_equal(tctx, k5ret, 0, error_string);
761 case TORTURE_KRB5_TEST_PLAIN:
762 case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
763 case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
764 case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
767 case TORTURE_KRB5_TEST_PAC_REQUEST:
768 torture_assert_int_equal(tctx,
769 krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options),
770 0, "krb5_get_init_creds_opt_alloc failed");
772 torture_assert_int_equal(tctx,
773 krb5_get_init_creds_opt_set_pac_request(smb_krb5_context->krb5_context, krb_options, true),
774 0, "krb5_get_init_creds_opt_set_pac_request failed");
777 case TORTURE_KRB5_TEST_BREAK_PW:
778 password = "NOT the password";
781 case TORTURE_KRB5_TEST_CLOCK_SKEW:
782 torture_assert_int_equal(tctx,
783 krb5_set_real_time(smb_krb5_context->krb5_context, time(NULL) + 3600, 0),
784 0, "krb5_set_real_time failed");
787 case TORTURE_KRB5_TEST_AES: {
788 static krb5_enctype etype_list[] = { KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 };
790 k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
792 torture_assert_int_equal(tctx,
794 "krb5_get_init_creds_opt_alloc failed");
796 krb5_get_init_creds_opt_set_etype_list(krb_options,
801 case TORTURE_KRB5_TEST_RC4: {
802 static krb5_enctype etype_list[] = { KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 };
804 k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
806 torture_assert_int_equal(tctx,
808 "krb5_get_init_creds_opt_alloc failed");
810 krb5_get_init_creds_opt_set_etype_list(krb_options,
815 case TORTURE_KRB5_TEST_AES_RC4: {
816 static krb5_enctype etype_list[] = { KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
817 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 };
819 k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
821 torture_assert_int_equal(tctx,
823 "krb5_get_init_creds_opt_alloc failed");
825 krb5_get_init_creds_opt_set_etype_list(krb_options,
833 k5ret = krb5_get_init_creds_password(smb_krb5_context->krb5_context, &my_creds, principal,
834 password, NULL, NULL, 0,
836 krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);
840 case TORTURE_KRB5_TEST_PLAIN:
841 case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
842 case TORTURE_KRB5_TEST_PAC_REQUEST:
843 case TORTURE_KRB5_TEST_AES:
844 case TORTURE_KRB5_TEST_RC4:
845 case TORTURE_KRB5_TEST_AES_RC4:
847 char *got_principal_string;
848 char *assertion_message;
849 torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed");
851 torture_assert_int_equal(tctx,
852 krb5_principal_get_type(k5_context,
855 "smb_krb5_init_context gave incorrect client->name.name_type");
857 torture_assert_int_equal(tctx,
858 krb5_unparse_name(k5_context,
860 &got_principal_string), 0,
861 "krb5_unparse_name failed");
863 assertion_message = talloc_asprintf(tctx,
864 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
865 got_principal_string, expected_principal_string);
866 krb5_xfree(got_principal_string);
868 torture_assert(tctx, krb5_principal_compare(k5_context,
874 torture_assert_str_equal(tctx,
875 my_creds.server->name.name_string.val[0],
877 "Mismatch in name between AS_REP and expected response, expected krbtgt");
878 torture_assert_str_equal(tctx,
879 my_creds.server->name.name_string.val[1],
881 "Mismatch in realm part of krbtgt/ in AS_REP, expected krbtgt/REALM@REALM");
883 torture_assert_str_equal(tctx,
884 my_creds.server->realm,
886 "Mismatch in server realm in AS_REP, expected krbtgt/REALM@REALM");
890 case TORTURE_KRB5_TEST_BREAK_PW:
891 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_PREAUTH_FAILED, "krb5_get_init_creds_password should have failed");
894 case TORTURE_KRB5_TEST_CLOCK_SKEW:
895 torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_SKEW, "krb5_get_init_creds_password should have failed");
898 case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
899 case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
901 char *got_principal_string;
902 char *assertion_message;
904 if (krb5_hostname[0] != '\0') {
905 torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_BAD_INTEGRITY, "krb5_get_init_creds_password should have failed");
909 torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed");
911 torture_assert_int_equal(tctx,
912 krb5_principal_get_type(k5_context,
915 "smb_krb5_init_context gave incorrect client->name.name_type");
917 torture_assert_int_equal(tctx,
918 krb5_unparse_name(k5_context,
920 &got_principal_string), 0,
921 "krb5_unparse_name failed");
923 assertion_message = talloc_asprintf(tctx,
924 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
925 got_principal_string, expected_principal_string);
926 krb5_xfree(got_principal_string);
928 torture_assert(tctx, krb5_principal_compare(k5_context,
937 k5ret = krb5_free_cred_contents(smb_krb5_context->krb5_context, &my_creds);
938 torture_assert_int_equal(tctx, k5ret, 0, "krb5_free_creds failed");
943 static bool torture_krb5_as_req_cmdline(struct torture_context *tctx)
945 return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
946 TORTURE_KRB5_TEST_PLAIN);
949 static bool torture_krb5_as_req_pac_request(struct torture_context *tctx)
951 if (torture_setting_bool(tctx, "expect_rodc", false)) {
952 torture_skip(tctx, "This test needs further investigation in the RODC case against a Windows DC, in particular with non-cached users");
954 return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
955 TORTURE_KRB5_TEST_PAC_REQUEST);
958 static bool torture_krb5_as_req_break_pw(struct torture_context *tctx)
960 return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
961 TORTURE_KRB5_TEST_BREAK_PW);
964 static bool torture_krb5_as_req_clock_skew(struct torture_context *tctx)
966 return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
967 TORTURE_KRB5_TEST_CLOCK_SKEW);
970 static bool torture_krb5_as_req_aes(struct torture_context *tctx)
972 return torture_krb5_as_req_creds(tctx,
973 samba_cmdline_get_creds(),
974 TORTURE_KRB5_TEST_AES);
977 static bool torture_krb5_as_req_rc4(struct torture_context *tctx)
979 return torture_krb5_as_req_creds(tctx,
980 samba_cmdline_get_creds(),
981 TORTURE_KRB5_TEST_RC4);
984 static bool torture_krb5_as_req_aes_rc4(struct torture_context *tctx)
986 return torture_krb5_as_req_creds(tctx,
987 samba_cmdline_get_creds(),
988 TORTURE_KRB5_TEST_AES_RC4);
991 /* Checking for the "Orpheus' Lyre" attack */
992 static bool torture_krb5_as_req_change_server_out(struct torture_context *tctx)
994 return torture_krb5_as_req_creds(tctx,
995 samba_cmdline_get_creds(),
996 TORTURE_KRB5_TEST_CHANGE_SERVER_OUT);
999 static bool torture_krb5_as_req_change_server_in(struct torture_context *tctx)
1001 return torture_krb5_as_req_creds(tctx,
1002 samba_cmdline_get_creds(),
1003 TORTURE_KRB5_TEST_CHANGE_SERVER_IN);
1006 static bool torture_krb5_as_req_change_server_both(struct torture_context *tctx)
1008 return torture_krb5_as_req_creds(tctx,
1009 samba_cmdline_get_creds(),
1010 TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH);
1013 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
1015 struct torture_suite *suite = torture_suite_create(ctx, "krb5");
1016 struct torture_suite *kdc_suite = torture_suite_create(suite, "kdc");
1017 suite->description = talloc_strdup(suite, "Kerberos tests");
1018 kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests");
1020 torture_suite_add_simple_test(kdc_suite, "as-req-cmdline",
1021 torture_krb5_as_req_cmdline);
1023 torture_suite_add_simple_test(kdc_suite, "as-req-pac-request",
1024 torture_krb5_as_req_pac_request);
1026 torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
1027 torture_krb5_as_req_break_pw);
1029 torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
1030 torture_krb5_as_req_clock_skew);
1032 torture_suite_add_simple_test(kdc_suite,
1034 torture_krb5_as_req_aes);
1036 torture_suite_add_simple_test(kdc_suite,
1038 torture_krb5_as_req_rc4);
1040 torture_suite_add_simple_test(kdc_suite,
1042 torture_krb5_as_req_aes_rc4);
1045 * This is in and out of the client.
1046 * Out refers to requests, in refers to replies
1048 torture_suite_add_simple_test(kdc_suite,
1049 "as-req-change-server-in",
1050 torture_krb5_as_req_change_server_in);
1052 torture_suite_add_simple_test(kdc_suite,
1053 "as-req-change-server-out",
1054 torture_krb5_as_req_change_server_out);
1056 torture_suite_add_simple_test(kdc_suite,
1057 "as-req-change-server-both",
1058 torture_krb5_as_req_change_server_both);
1060 torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
1061 torture_suite_add_suite(suite, kdc_suite);
1063 torture_register_suite(ctx, suite);
1064 return NT_STATUS_OK;