From: Greg Hudson Date: Sat, 6 Jun 2015 01:19:15 +0000 (-0400) Subject: Add tests for KDC etype-info behavior X-Git-Tag: krb5-1.14-alpha1~79 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5cf4a7e220141f10f51995ceae9b9e74232a31b7;p=thirdparty%2Fkrb5.git Add tests for KDC etype-info behavior Create a new test harness etinfo.c which can display etype-info2 information in KDC responses. Use it to test the etype-info results in preauth_required error e-data and AS-REP padata. ticket: 8199 --- diff --git a/.gitignore b/.gitignore index d9ceb213a0..090dc90716 100644 --- a/.gitignore +++ b/.gitignore @@ -250,6 +250,7 @@ testlog /src/slave/kproplog /src/tests/adata +/src/tests/etinfo /src/tests/gcred /src/tests/hist /src/tests/hrealm diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index 121c1e1f7e..602d74a27a 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -5,9 +5,9 @@ SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \ RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf -OBJS= adata.o gcred.o hist.o hrealm.o kdbtest.o plugorder.o t_init_creds.o \ - t_localauth.o rdreq.o responder.o s2p.o -EXTRADEPSRCS= adata.c gcred.c hist.c hrealm.c kdbtest.c plugorder.c \ +OBJS= adata.o etinfo.o gcred.o hist.o hrealm.o kdbtest.o plugorder.o \ + t_init_creds.o t_localauth.o rdreq.o responder.o s2p.o +EXTRADEPSRCS= adata.c etinfo.c gcred.c hist.c hrealm.c kdbtest.c plugorder.c \ t_init_creds.c t_localauth.c rdreq.o responder.c s2p.c TEST_DB = ./testdb @@ -23,6 +23,9 @@ KTEST_OPTS= $(KADMIN_OPTS) -p $(TEST_PREFIX) -n $(TEST_NUM) -D $(TEST_DEPTH) adata: adata.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ adata.o $(KRB5_BASE_LIBS) +etinfo: etinfo.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ etinfo.o $(KRB5_BASE_LIBS) + gcred: gcred.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ gcred.o $(KRB5_BASE_LIBS) @@ -100,8 +103,8 @@ kdb_check: kdc.conf krb5.conf $(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f $(RM) $(TEST_DB)* stash_file -check-pytests:: adata gcred hist hrealm kdbtest plugorder rdreq responder -check-pytests:: s2p t_init_creds t_localauth unlockiter +check-pytests:: adata etinfo gcred hist hrealm kdbtest plugorder rdreq +check-pytests:: responder s2p t_init_creds t_localauth unlockiter $(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS) @@ -140,6 +143,7 @@ check-pytests:: s2p t_init_creds t_localauth unlockiter $(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \ -i au.log $(RUNPYTEST) $(srcdir)/t_salt.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_etype_info.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_bogus_kdc_req.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_kdc_log.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_proxy.py $(PYTESTFLAGS) @@ -148,7 +152,8 @@ check-pytests:: s2p t_init_creds t_localauth unlockiter $(RUNPYTEST) $(srcdir)/t_authdata.py $(PYTESTFLAGS) clean:: - $(RM) adata gcred hist hrealm kdbtest plugorder rdreq responder s2p - $(RM) t_init_creds t_localauth krb5.conf kdc.conf + $(RM) gcred hist hrealm kdbtest plugorder rdreq responder s2p + $(RM) adata etinfo gcred hist hrealm kdbtest plugorder rdreq responder + $(RM) s2p t_init_creds t_localauth krb5.conf kdc.conf $(RM) -rf kdc_realm/sandbox ldap $(RM) au.log diff --git a/src/tests/etinfo.c b/src/tests/etinfo.c new file mode 100644 index 0000000000..dc4563877a --- /dev/null +++ b/src/tests/etinfo.c @@ -0,0 +1,166 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* tests/etinfo.c - Test harness for KDC etype-info behavior */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Send an AS-REQ to the KDC for a specified principal, with an optionally + * specified request enctype list. Decode the output as either an AS-REP or a + * KRB-ERROR and display the PA-ETYPE-INFO2, PA-ETYPE-INFO, and PA-PW-SALT + * padata in the following format: + * + * error/asrep etype-info2/etype-info/pw-salt enctype salt [s2kparams] + * + * enctype is omitted for PA-PW-SALT entries. salt is displayed directly; + * s2kparams is displayed in uppercase hex. + */ + +#include "k5-int.h" + +static krb5_context ctx; + +static void +check(krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(ctx, code); + fprintf(stderr, "%s\n", errmsg); + krb5_free_error_message(ctx, errmsg); + exit(1); + } +} + +static void +display_etinfo(krb5_etype_info_entry **list, const char *l1, const char *l2) +{ + krb5_etype_info_entry *info; + char etname[256]; + unsigned int i; + + for (; *list != NULL; list++) { + info = *list; + check(krb5_enctype_to_name(info->etype, TRUE, etname, sizeof(etname))); + printf("%s %s %s ", l1, l2, etname); + if (info->length != KRB5_ETYPE_NO_SALT) + printf("%.*s", info->length, info->salt); + else + printf("(default)"); + if (info->s2kparams.length > 0) { + printf(" "); + for (i = 0; i < info->s2kparams.length; i++) + printf("%02X", (unsigned char)info->s2kparams.data[i]); + } + printf("\n"); + } +} + +static void +display_padata(krb5_pa_data **pa_list, const char *label) +{ + krb5_pa_data *pa; + krb5_data d; + krb5_etype_info_entry **etinfo_list; + + for (; pa_list != NULL && *pa_list != NULL; pa_list++) { + pa = *pa_list; + d = make_data(pa->contents, pa->length); + if (pa->pa_type == KRB5_PADATA_ETYPE_INFO2) { + check(decode_krb5_etype_info2(&d, &etinfo_list)); + display_etinfo(etinfo_list, label, "etype_info2"); + krb5_free_etype_info(ctx, etinfo_list); + } else if (pa->pa_type == KRB5_PADATA_ETYPE_INFO) { + check(decode_krb5_etype_info(&d, &etinfo_list)); + display_etinfo(etinfo_list, label, "etype_info"); + krb5_free_etype_info(ctx, etinfo_list); + } else if (pa->pa_type == KRB5_PADATA_PW_SALT) { + printf("%s pw_salt %.*s\n", label, (int)d.length, d.data); + } else if (pa->pa_type == KRB5_PADATA_AFS3_SALT) { + printf("%s afs3_salt %.*s\n", label, (int)d.length, d.data); + } + } +} + +int +main(int argc, char **argv) +{ + krb5_principal client; + krb5_init_creds_context icc; + krb5_data reply, request, realm; + krb5_error *error; + krb5_kdc_rep *asrep; + krb5_pa_data **padata; + krb5_enctype *enctypes, def[] = { ENCTYPE_NULL }; + unsigned int flags; + int master = 0; + + if (argc < 2 && argc > 3) { + fprintf(stderr, "Usage: %s princname [enctypes]\n", argv[0]); + exit(1); + } + check(krb5_init_context(&ctx)); + check(krb5_parse_name(ctx, argv[1], &client)); + if (argc >= 3) { + check(krb5int_parse_enctype_list(ctx, "", argv[2], def, &enctypes)); + krb5_set_default_in_tkt_ktypes(ctx, enctypes); + free(enctypes); + } + + check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc)); + reply = empty_data(); + check(krb5_init_creds_step(ctx, icc, &reply, &request, &realm, &flags)); + assert(flags == KRB5_INIT_CREDS_STEP_FLAG_CONTINUE); + check(krb5_sendto_kdc(ctx, &request, &realm, &reply, &master, 0)); + + if (decode_krb5_error(&reply, &error) == 0) { + decode_krb5_padata_sequence(&error->e_data, &padata); + if (error->error != KDC_ERR_PREAUTH_REQUIRED) { + fprintf(stderr, "Unexpected error %d\n", (int)error->error); + return 1; + } + display_padata(padata, "error"); + krb5_free_pa_data(ctx, padata); + krb5_free_error(ctx, error); + } else if (decode_krb5_as_rep(&reply, &asrep) == 0) { + display_padata(asrep->padata, "asrep"); + krb5_free_kdc_rep(ctx, asrep); + } else { + abort(); + } + + krb5_free_data_contents(ctx, &request); + krb5_free_data_contents(ctx, &reply); + krb5_free_data_contents(ctx, &realm); + krb5_init_creds_free(ctx, icc); + krb5_free_principal(ctx, client); + krb5_free_context(ctx); + return 0; +} diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py new file mode 100644 index 0000000000..8ff6ad6664 --- /dev/null +++ b/src/tests/t_etype_info.py @@ -0,0 +1,76 @@ +#!/usr/bin/python +from k5test import * + +supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac des-cbc-crc:afs3' +conf = {'libdefaults': {'allow_weak_crypto': 'true'}, + 'realms': {'$realm': {'supported_enctypes': supported_enctypes}}} +realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf) + +realm.run([kadminl, 'addprinc', '-pw', 'pw', '+requires_preauth', + 'preauthuser']) +realm.run([kadminl, 'addprinc', '-pw', 'pw', '-e', 'rc4-hmac', + '+requires_preauth', 'rc4user']) +realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser']) + + +# Run the test harness for the given principal and request enctype +# list. Compare the output to the expected lines, ignoring order. +def test_etinfo(princ, enctypes, expected_lines): + lines = realm.run(['./etinfo', princ, enctypes]).splitlines() + if sorted(lines) != sorted(expected_lines): + fail('Unexpected output for princ %s, etypes %s' % (princ, enctypes)) + + +# With no newer enctypes in the request, PA-ETYPE-INFO2, +# PA-ETYPE-INFO, and PA-PW-SALT appear in the AS-REP, each listing one +# key for the most preferred matching enctype. +test_etinfo('user', 'rc4-hmac-exp des3 rc4 des-cbc-crc', + ['asrep etype_info2 des3-cbc-sha1 KRBTEST.COMuser', + 'asrep etype_info des3-cbc-sha1 KRBTEST.COMuser', + 'asrep pw_salt KRBTEST.COMuser']) + +# With a newer enctype in the request (even if it is not the most +# preferred enctype and doesn't match any keys), only PA-ETYPE-INFO2 +# appears. +test_etinfo('user', 'rc4 aes256-cts', + ['asrep etype_info2 rc4-hmac KRBTEST.COMuser']) + +# In preauth-required errors, PA-PW-SALT does not appear, but the same +# etype-info2 values are expected. +test_etinfo('preauthuser', 'rc4-hmac-exp des3 rc4 des-cbc-crc', + ['error etype_info2 des3-cbc-sha1 KRBTEST.COMpreauthuser', + 'error etype_info des3-cbc-sha1 KRBTEST.COMpreauthuser']) +test_etinfo('preauthuser', 'rc4 aes256-cts', + ['error etype_info2 rc4-hmac KRBTEST.COMpreauthuser']) + +# AFS3 salt for DES enctypes is conveyed using s2kparams in +# PA-ETYPE-INFO2, not at all in PA-ETYPE-INFO, and with a special padata +# type instead of PA-PW-SALT. +test_etinfo('user', 'des-cbc-crc rc4', + ['asrep etype_info2 des-cbc-crc KRBTEST.COM 01', + 'asrep etype_info des-cbc-crc KRBTEST.COM', + 'asrep afs3_salt KRBTEST.COM']) +test_etinfo('preauthuser', 'des-cbc-crc rc4', + ['error etype_info2 des-cbc-crc KRBTEST.COM 01', + 'error etype_info des-cbc-crc KRBTEST.COM']) + +# DES keys can be used with other DES enctypes. The requested enctype +# shows up in the etype-info, not the database key enctype. +test_etinfo('user', 'des-cbc-md4 rc4', + ['asrep etype_info2 des-cbc-md4 KRBTEST.COM 01', + 'asrep etype_info des-cbc-md4 KRBTEST.COM', + 'asrep afs3_salt KRBTEST.COM']) +test_etinfo('user', 'des-cbc-md5 rc4', + ['asrep etype_info2 des KRBTEST.COM 01', + 'asrep etype_info des KRBTEST.COM', + 'asrep afs3_salt KRBTEST.COM']) + +# If no keys are found matching the request enctypes, a +# preauth-required error can be generated with no etype-info at all +# (to allow for preauth mechs which don't depend on long-term keys). +# An AS-REP cannot be generated without preauth as there is no reply +# key. +test_etinfo('rc4user', 'des3', []) +test_etinfo('nokeyuser', 'des3', []) + +success('KDC etype-info tests')