From: Greg Hudson Date: Sun, 15 Mar 2015 19:56:34 +0000 (-0400) Subject: Test client_keyblock kdcpreauth callback X-Git-Tag: krb5-1.14-alpha1~77 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be20a5f5cee8d6c4072d1b81712520dbf9f6eefd;p=thirdparty%2Fkrb5.git Test client_keyblock kdcpreauth callback Add internal clpreauth and kdcpreauth modules named "test" which can exercise the client_keyblock callback (as well as get_string and get_as_key on the client side). Add tests to t_etype_info.py to verify that the callback matches the etype info sent by the KDC. In the KDC's load_preauth_plugins(), correct a test for the end of pa_type_list so that we can use a negative preauth type number for the test module. (RFC 4120 reserves negative preauth type values for unregistered use.) ticket: 8200 --- diff --git a/src/Makefile.in b/src/Makefile.in index 3c81b22aa3..3f57573fd6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -22,6 +22,7 @@ SUBDIRS=util include lib \ plugins/kdb/test \ plugins/preauth/otp \ plugins/preauth/pkinit \ + plugins/preauth/test \ plugins/tls/k5tls \ kdc kadmin slave clients appl tests \ config-files build-tools man doc @po@ diff --git a/src/configure.in b/src/configure.in index 13a9b58a15..d3938fce27 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1450,6 +1450,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test plugins/preauth/cksum_body plugins/preauth/otp plugins/preauth/securid_sam2 + plugins/preauth/test plugins/preauth/wpse plugins/authdata/greet_client plugins/authdata/greet_server diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index d76d4af169..34775f36ce 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -323,7 +323,7 @@ load_preauth_plugins(struct server_handle *handle, krb5_context context, } /* Add this module to the systems list once for each pa type. */ - for (j = 0; vt->pa_type_list[j] > 0; j++) { + for (j = 0; vt->pa_type_list[j] != 0; j++) { sys = &preauth_systems[n_systems]; sys->name = vt->name; sys->type = vt->pa_type_list[j]; diff --git a/src/plugins/preauth/test/Makefile.in b/src/plugins/preauth/test/Makefile.in new file mode 100644 index 0000000000..bcb25c5f8c --- /dev/null +++ b/src/plugins/preauth/test/Makefile.in @@ -0,0 +1,21 @@ +mydir=plugins$(S)preauth$(S)test +BUILDTOP=$(REL)..$(S)..$(S).. +MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) + +LIBBASE=test +LIBMAJOR=0 +LIBMINOR=0 +RELDIR=../plugins/preauth/test +SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) +SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) + +STLIBOBJS=cltest.o kdctest.o + +SRCS= $(srcdir)/cltest.c $(srcdir)/kdctest.c + +all-unix:: all-liblinks +install-unix:: install-libs +clean-unix:: clean-libs clean-libobjs + +@libnover_frag@ +@libobj_frag@ diff --git a/src/plugins/preauth/test/cltest.c b/src/plugins/preauth/test/cltest.c new file mode 100644 index 0000000000..fe63ed98c5 --- /dev/null +++ b/src/plugins/preauth/test/cltest.c @@ -0,0 +1,107 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/test/cltest.c - Test clpreauth module */ +/* + * 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. + */ + +/* + * This module is used to test preauth interface features. At this time, the + * clpreauth module decrypts a message from the initial KDC padata using the + * reply key and prints it to stdout. (The unencrypted message "no key" can + * also be displayed.) An empty padata message is then sent to the KDC. + */ + +#include "k5-int.h" +#include + +#define TEST_PA_TYPE -123 + +static krb5_preauthtype pa_types[] = { TEST_PA_TYPE, 0 }; + +static krb5_error_code +test_process(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *request, krb5_data *encoded_request_body, + krb5_data *encoded_previous_request, krb5_pa_data *pa_data, + krb5_prompter_fct prompter, void *prompter_data, + krb5_pa_data ***out_pa_data) +{ + krb5_error_code ret; + krb5_pa_data **list, *pa; + krb5_keyblock *k; + krb5_enc_data enc; + krb5_data plain; + + if (pa_data->length == 6 && memcmp(pa_data->contents, "no key", 6) == 0) { + printf("no key\n"); + } else { + ret = cb->get_as_key(context, rock, &k); + assert(!ret); + ret = alloc_data(&plain, pa_data->length); + assert(!ret); + enc.enctype = k->enctype; + enc.ciphertext = make_data(pa_data->contents, pa_data->length); + ret = krb5_c_decrypt(context, k, 1024, NULL, &enc, &plain); + assert(!ret); + printf("%.*s\n", plain.length, plain.data); + free(plain.data); + } + + list = k5calloc(2, sizeof(*list), &ret); + assert(!ret); + pa = k5alloc(sizeof(*pa), &ret); + assert(!ret); + pa->pa_type = TEST_PA_TYPE; + pa->contents = NULL; + pa->length = 0; + list[0] = pa; + list[1] = NULL; + *out_pa_data = list; + return 0; +} + +krb5_error_code +clpreauth_test_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); + +krb5_error_code +clpreauth_test_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable) +{ + krb5_clpreauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_clpreauth_vtable)vtable; + vt->name = "test"; + vt->pa_type_list = pa_types; + vt->process = test_process; + return 0; +} diff --git a/src/plugins/preauth/test/deps b/src/plugins/preauth/test/deps new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/plugins/preauth/test/kdctest.c b/src/plugins/preauth/test/kdctest.c new file mode 100644 index 0000000000..ba5125ad62 --- /dev/null +++ b/src/plugins/preauth/test/kdctest.c @@ -0,0 +1,137 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/test/kdctest.c - Test kdcpreauth module */ +/* + * 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. + */ + +/* + * This module is used to test preauth interface features. Currently, it + * retrieves the "teststring" attribute from the client principal and sends it + * to the client, encrypted in the reply key. (The plain text "no key" is sent + * if there is no reply key; the encrypted message "no attr" is sent if there + * is no string attribute.) Upon receiving padata from the client, it always + * succeeds in preauthenticating the request. + * + * To use this module, a test script should: + * - Register this module and the corresponding clpreauth module + * - Disable the encrypted_timestamp clpreauth or kdcpreauth module + * - Set the requires_preauth flag on the client principal + */ + +#include "k5-int.h" +#include + +#define TEST_PA_TYPE -123 + +static krb5_preauthtype pa_types[] = { TEST_PA_TYPE, 0 }; + +static void +test_edata(krb5_context context, krb5_kdc_req *req, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, + krb5_kdcpreauth_edata_respond_fn respond, void *arg) +{ + krb5_error_code ret; + const krb5_keyblock *k = cb->client_keyblock(context, rock); + krb5_pa_data *pa; + size_t enclen; + krb5_enc_data enc; + krb5_data d; + char *attr; + + ret = cb->get_string(context, rock, "teststring", &attr); + assert(!ret); + pa = k5alloc(sizeof(*pa), &ret); + assert(!ret); + if (pa == NULL) + abort(); + pa->pa_type = TEST_PA_TYPE; + if (k != NULL) { + d = string2data((attr != NULL) ? attr : "no attr"); + ret = krb5_c_encrypt_length(context, k->enctype, d.length, &enclen); + assert(!ret); + ret = alloc_data(&enc.ciphertext, enclen); + assert(!ret); + ret = krb5_c_encrypt(context, k, 1024, NULL, &d, &enc); + assert(!ret); + pa->contents = (uint8_t *)enc.ciphertext.data; + pa->length = enc.ciphertext.length; + } else { + pa->contents = (uint8_t *)strdup("no key"); + assert(pa->contents != NULL); + pa->length = 6; + } + cb->free_string(context, rock, attr); + (*respond)(arg, 0, pa); +} + +static void +test_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + (*respond)(arg, 0, NULL, NULL, NULL); +} + +static krb5_error_code +test_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt, + krb5_kdc_req *request, krb5_kdc_rep *reply, + krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) +{ + const krb5_keyblock *k = cb->client_keyblock(context, rock); + + assert(k == encrypting_key || k == NULL); + return 0; +} + +krb5_error_code +kdcpreauth_test_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); + +krb5_error_code +kdcpreauth_test_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable) +{ + krb5_kdcpreauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_kdcpreauth_vtable)vtable; + vt->name = "test"; + vt->pa_type_list = pa_types; + vt->edata = test_edata; + vt->verify = test_verify; + vt->return_padata = test_return; + return 0; +} diff --git a/src/plugins/preauth/test/test.exports b/src/plugins/preauth/test/test.exports new file mode 100644 index 0000000000..94ba37491d --- /dev/null +++ b/src/plugins/preauth/test/test.exports @@ -0,0 +1,2 @@ +clpreauth_test_initvt +kdcpreauth_test_initvt diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py index 8ff6ad6664..a3eaac2836 100644 --- a/src/tests/t_etype_info.py +++ b/src/tests/t_etype_info.py @@ -73,4 +73,25 @@ test_etinfo('user', 'des-cbc-md5 rc4', test_etinfo('rc4user', 'des3', []) test_etinfo('nokeyuser', 'des3', []) +realm.stop() + +# Test that the kdcpreauth client_keyblock() callback matches the key +# indicated by the etype info, and returns NULL if key was selected. +testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so') +plugconf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth}, + 'clpreauth': {'module': 'test:' + testpreauth, + 'disable': 'encrypted_timestamp'}}} +conf.update(plugconf) +realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf) +realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ]) +realm.run([kadminl, 'setstr', realm.user_princ, 'teststring', 'testval']) +realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser']) +out = realm.run([kinit, realm.user_princ], input=password('user')+'\n') +if 'testval' not in out: + fail('Decrypted string attribute not in kinit output') +out = realm.run([kinit, 'nokeyuser'], input=password('user')+'\n', + expected_code=1) +if 'no key' not in out: + fail('Expected "no key" message not in kinit output') + success('KDC etype-info tests')