From ed118374c6fdfbd04ee56d241ab378714077bb6d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 12 Jul 2017 23:11:32 +1200 Subject: [PATCH] s4-smbtorture: Add test krb5.kdc to prove fix for CVE-2017-11103 Signed-off-by: Andrew Bartlett --- source4/torture/krb5/kdc-heimdal.c | 100 ++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/source4/torture/krb5/kdc-heimdal.c b/source4/torture/krb5/kdc-heimdal.c index 7d786dc..af41c21 100644 --- a/source4/torture/krb5/kdc-heimdal.c +++ b/source4/torture/krb5/kdc-heimdal.c @@ -437,8 +437,9 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex "Too many packets"); break; case TORTURE_KRB5_TEST_CHANGE_SERVER_IN: + case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH: { - AS_REQ mod_as_req; + AS_REP mod_as_rep; krb5_error_code k5ret; krb5_data modified_recv_buf; if (test_context->packet_count == 0) { @@ -468,31 +469,30 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex test_context->as_rep.ticket.tkt_vno, 5, "Got wrong as_rep->ticket.tkt_vno"); torture_assert_int_equal(test_context->tctx, - test_context->as_rep.ticket.sname.len, 2, - "Got wrong as_rep->ticket.sname.len"); - free(test_context->as_rep.ticket.sname.val[0]); - free(test_context->as_rep.ticket.sname.val[1]); + test_context->as_rep.ticket.sname.name_string.len, 2, + "Got wrong as_rep->ticket.sname.name_string.len"); + free(test_context->as_rep.ticket.sname.name_string.val[0]); + free(test_context->as_rep.ticket.sname.name_string.val[1]); test_context->as_rep.ticket.sname.name_string.val[0] = strdup("bad"); - test_context->as_rep.ticket.sname.name_string.val[0] = strdup("mallory"); + test_context->as_rep.ticket.sname.name_string.val[1] = strdup("mallory"); - free_AS_REP(&test_context->as_rep); + mod_as_rep = test_context->as_rep; + + ASN1_MALLOC_ENCODE(AS_REP, modified_recv_buf.data, modified_recv_buf.length, + &mod_as_rep, &used, k5ret); + torture_assert_int_equal(test_context->tctx, + k5ret, 0, + "encode_AS_REQ failed"); + krb5_data_free(recv_buf); + + *recv_buf = modified_recv_buf; + free_AS_REQ(&test_context->as_req); } torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets"); - - ASN1_MALLOC_ENCODE(AS_REQ, modified_recv_buf->data, modified_recv_buf->length, - &mod_as_req, &used, k5ret); - torture_assert_int_equal(test_context->tctx, - k5ret, 0, - "encode_AS_REQ failed"); - krb5_data_free(*recv_buf); - - *recv_buf = modified_recv_buf; - free_AS_REQ(&test_context->as_req); - break; - case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH: break; } + } return true; @@ -593,14 +593,23 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx, krb5_creds my_creds; krb5_principal principal; struct smb_krb5_context *smb_krb5_context; + krb5_context k5_context; enum credentials_obtained obtained; const char *error_string; const char *password = cli_credentials_get_password(credentials); + const char *expected_principal_string; krb5_get_init_creds_opt *krb_options = NULL; - + const char *realm; + ok = torture_krb5_init_context(tctx, test, &smb_krb5_context); torture_assert(tctx, ok, "torture_krb5_init_context failed"); - + k5_context = smb_krb5_context->krb5_context; + + expected_principal_string + = cli_credentials_get_principal(credentials, + tctx); + + realm = strupper_talloc(tctx, cli_credentials_get_realm(credentials)); k5ret = principal_from_credentials(tctx, credentials, smb_krb5_context, &principal, &obtained, &error_string); torture_assert_int_equal(tctx, k5ret, 0, error_string); @@ -687,16 +696,55 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx, switch (test) { case TORTURE_KRB5_TEST_PLAIN: - case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT: case TORTURE_KRB5_TEST_CHANGE_SERVER_IN: - case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH: case TORTURE_KRB5_TEST_PAC_REQUEST: case TORTURE_KRB5_TEST_AES: case TORTURE_KRB5_TEST_RC4: case TORTURE_KRB5_TEST_AES_RC4: + { + char *got_principal_string; + char *assertion_message; torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed"); - break; + + torture_assert_int_equal(tctx, + krb5_principal_get_type(k5_context, + my_creds.client), + KRB5_NT_PRINCIPAL, + "smb_krb5_init_context gave incorrect client->name.name_type"); + + torture_assert_int_equal(tctx, + krb5_unparse_name(k5_context, + my_creds.client, + &got_principal_string), 0, + "krb5_unparse_name failed"); + + assertion_message = talloc_asprintf(tctx, + "krb5_get_init_creds_password returned a different principal %s to what was expected %s", + got_principal_string, expected_principal_string); + krb5_free_unparsed_name(k5_context, got_principal_string); + + torture_assert(tctx, krb5_principal_compare(k5_context, + my_creds.client, + principal), + assertion_message); + + + torture_assert_str_equal(tctx, + my_creds.server->name.name_string.val[0], + "krbtgt", + "Mismatch in name between AS_REP and expected response, expected krbtgt"); + torture_assert_str_equal(tctx, + my_creds.server->name.name_string.val[1], + realm, + "Mismatch in realm part of krbtgt/ in AS_REP, expected krbtgt/REALM@REALM"); + + torture_assert_str_equal(tctx, + my_creds.server->realm, + realm, + "Mismatch in server realm in AS_REP, expected krbtgt/REALM@REALM"); + break; + } case TORTURE_KRB5_TEST_BREAK_PW: torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_PREAUTH_FAILED, "krb5_get_init_creds_password should have failed"); return true; @@ -705,6 +753,10 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx, torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_SKEW, "krb5_get_init_creds_password should have failed"); return true; + case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT: + case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH: + torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed"); + break; } k5ret = krb5_free_cred_contents(smb_krb5_context->krb5_context, &my_creds); -- 2.9.5