Path: blob/main/crypto/krb5/src/plugins/preauth/test/kdctest.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* plugins/preauth/test/kdctest.c - Test kdcpreauth module */2/*3* Copyright (C) 2015, 2017 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132/*33* This module is used to test preauth interface features. Currently, the34* kdcpreauth module does the following:35*36* - When generating initial method-data, it retrieves the "teststring"37* attribute from the client principal and sends it to the client, encrypted38* in the reply key. (The plain text "no key" is sent if there is no reply39* key; the encrypted message "no attr" is sent if there is no string40* attribute.) It also sets a cookie containing "method-data".41*42* - If the "err" attribute is set on the client principal, the verify method43* returns an KDC_ERR_ETYPE_NOSUPP error on the first try, with the contents44* of the err attribute as pa-data. If the client tries again with the45* padata value "tryagain", the verify method preuthenticates successfully46* with no additional processing.47*48* - If the "failopt" attribute is set on the client principal, the verify49* method returns KDC_ERR_PREAUTH_FAILED on optimistic preauth attempts.50*51* - If the "2rt" attribute is set on client principal, the verify method sends52* the client a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with the contents of53* the 2rt attribute as pa-data, and sets a cookie containing "more". If the54* "fail2rt" attribute is set on the client principal, the client's second55* try results in a KDC_ERR_PREAUTH_FAILED error.56*57* - It receives a space-separated list from the clpreauth module and asserts58* each string as an authentication indicator. It always succeeds in59* pre-authenticating the request.60*/6162#include "k5-int.h"63#include <krb5/kdcpreauth_plugin.h>64#include "common.h"6566#define TEST_PA_TYPE -1236768static krb5_preauthtype pa_types[] = { TEST_PA_TYPE, 0 };6970static void71test_edata(krb5_context context, krb5_kdc_req *req,72krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,73krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,74krb5_kdcpreauth_edata_respond_fn respond, void *arg)75{76krb5_error_code ret;77const krb5_keyblock *k = cb->client_keyblock(context, rock);78krb5_pa_data *pa;79size_t enclen;80krb5_enc_data enc;81krb5_data d;82char *attr;8384ret = cb->get_string(context, rock, "teststring", &attr);85assert(!ret);86if (k != NULL) {87d = string2data((attr != NULL) ? attr : "no attr");88ret = krb5_c_encrypt_length(context, k->enctype, d.length, &enclen);89assert(!ret);90ret = alloc_data(&enc.ciphertext, enclen);91assert(!ret);92ret = krb5_c_encrypt(context, k, 1024, NULL, &d, &enc);93assert(!ret);94pa = make_pa(enc.ciphertext.data, enc.ciphertext.length);95free(enc.ciphertext.data);96} else {97pa = make_pa("no key", 6);98}99100/* Exercise setting a cookie information from the edata method. */101d = string2data("method-data");102ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);103assert(!ret);104105cb->free_string(context, rock, attr);106(*respond)(arg, 0, pa);107}108109static void110test_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,111krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,112krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,113krb5_kdcpreauth_moddata moddata,114krb5_kdcpreauth_verify_respond_fn respond, void *arg)115{116krb5_error_code ret;117krb5_boolean second_round_trip = FALSE, optimistic = FALSE;118krb5_pa_data **list = NULL;119krb5_data cookie_data, d;120char *str, *ind, *toksave = NULL;121char *attr_err, *attr_2rt, *attr_fail2rt, *attr_failopt;122123ret = cb->get_string(context, rock, "err", &attr_err);124assert(!ret);125ret = cb->get_string(context, rock, "2rt", &attr_2rt);126assert(!ret);127ret = cb->get_string(context, rock, "fail2rt", &attr_fail2rt);128assert(!ret);129ret = cb->get_string(context, rock, "failopt", &attr_failopt);130assert(!ret);131132/* Check the incoming cookie value. */133if (!cb->get_cookie(context, rock, TEST_PA_TYPE, &cookie_data)) {134/* Make sure we are seeing optimistic preauth and not a lost cookie. */135d = make_data(data->contents, data->length);136assert(data_eq_string(d, "optimistic"));137optimistic = TRUE;138} else if (data_eq_string(cookie_data, "more")) {139second_round_trip = TRUE;140} else {141assert(data_eq_string(cookie_data, "method-data") ||142data_eq_string(cookie_data, "err"));143}144145if (attr_err != NULL) {146d = make_data(data->contents, data->length);147if (data_eq_string(d, "tryagain")) {148/* Authenticate successfully. */149enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;150} else {151d = string2data("err");152ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);153assert(!ret);154ret = KRB5KDC_ERR_ETYPE_NOSUPP;155list = make_pa_list(attr_err, strlen(attr_err));156}157} else if (attr_2rt != NULL && !second_round_trip) {158d = string2data("more");159ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);160assert(!ret);161ret = KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;162list = make_pa_list(attr_2rt, strlen(attr_2rt));163} else if ((attr_fail2rt != NULL && second_round_trip) ||164(attr_failopt != NULL && optimistic)) {165ret = KRB5KDC_ERR_PREAUTH_FAILED;166} else {167/* Parse and assert the indicators. */168str = k5memdup0(data->contents, data->length, &ret);169if (ret)170abort();171ind = strtok_r(str, " ", &toksave);172while (ind != NULL) {173cb->add_auth_indicator(context, rock, ind);174ind = strtok_r(NULL, " ", &toksave);175}176free(str);177enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;178}179180cb->free_string(context, rock, attr_err);181cb->free_string(context, rock, attr_2rt);182cb->free_string(context, rock, attr_fail2rt);183cb->free_string(context, rock, attr_failopt);184(*respond)(arg, ret, NULL, list, NULL);185}186187static krb5_error_code188test_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,189krb5_kdc_req *request, krb5_kdc_rep *reply,190krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out,191krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,192krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)193{194const krb5_keyblock *k = cb->client_keyblock(context, rock);195196assert(k == encrypting_key || k == NULL);197return 0;198}199200krb5_error_code201kdcpreauth_test_initvt(krb5_context context, int maj_ver,202int min_ver, krb5_plugin_vtable vtable);203204krb5_error_code205kdcpreauth_test_initvt(krb5_context context, int maj_ver,206int min_ver, krb5_plugin_vtable vtable)207{208krb5_kdcpreauth_vtable vt;209210if (maj_ver != 1)211return KRB5_PLUGIN_VER_NOTSUPP;212vt = (krb5_kdcpreauth_vtable)vtable;213vt->name = "test";214vt->pa_type_list = pa_types;215vt->edata = test_edata;216vt->verify = test_verify;217vt->return_padata = test_return;218return 0;219}220221222