Blame src/plugins/preauth/test/kdctest.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* plugins/preauth/test/kdctest.c - Test kdcpreauth module */
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 2015, 2017 by the Massachusetts Institute of Technology.
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Redistribution and use in source and binary forms, with or without
Packit fd8b60
 * modification, are permitted provided that the following conditions
Packit fd8b60
 * are met:
Packit fd8b60
 *
Packit fd8b60
 * * Redistributions of source code must retain the above copyright
Packit fd8b60
 *   notice, this list of conditions and the following disclaimer.
Packit fd8b60
 *
Packit fd8b60
 * * Redistributions in binary form must reproduce the above copyright
Packit fd8b60
 *   notice, this list of conditions and the following disclaimer in
Packit fd8b60
 *   the documentation and/or other materials provided with the
Packit fd8b60
 *   distribution.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit fd8b60
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit fd8b60
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit fd8b60
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit fd8b60
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit fd8b60
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit fd8b60
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit fd8b60
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit fd8b60
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit fd8b60
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit fd8b60
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit fd8b60
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * This module is used to test preauth interface features.  Currently, the
Packit fd8b60
 * kdcpreauth module does the following:
Packit fd8b60
 *
Packit fd8b60
 * - When generating initial method-data, it retrieves the "teststring"
Packit fd8b60
 *   attribute from the client principal and sends it to the client, encrypted
Packit fd8b60
 *   in the reply key.  (The plain text "no key" is sent if there is no reply
Packit fd8b60
 *   key; the encrypted message "no attr" is sent if there is no string
Packit fd8b60
 *   attribute.)  It also sets a cookie containing "method-data".
Packit fd8b60
 *
Packit fd8b60
 * - If the "err" attribute is set on the client principal, the verify method
Packit fd8b60
 *   returns an KDC_ERR_ETYPE_NOSUPP error on the first try, with the contents
Packit fd8b60
 *   of the err attribute as pa-data.  If the client tries again with the
Packit fd8b60
 *   padata value "tryagain", the verify method preuthenticates successfully
Packit fd8b60
 *   with no additional processing.
Packit fd8b60
 *
Packit fd8b60
 * - If the "failopt" attribute is set on the client principal, the verify
Packit fd8b60
 *   method returns KDC_ERR_PREAUTH_FAILED on optimistic preauth attempts.
Packit fd8b60
 *
Packit fd8b60
 * - If the "2rt" attribute is set on client principal, the verify method sends
Packit fd8b60
 *   the client a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with the contents of
Packit fd8b60
 *   the 2rt attribute as pa-data, and sets a cookie containing "more".  If the
Packit fd8b60
 *   "fail2rt" attribute is set on the client principal, the client's second
Packit fd8b60
 *   try results in a KDC_ERR_PREAUTH_FAILED error.
Packit fd8b60
 *
Packit fd8b60
 * - It receives a space-separated list from the clpreauth module and asserts
Packit fd8b60
 *   each string as an authentication indicator.  It always succeeds in
Packit fd8b60
 *   pre-authenticating the request.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include "k5-int.h"
Packit fd8b60
#include <krb5/kdcpreauth_plugin.h>
Packit fd8b60
#include "common.h"
Packit fd8b60
Packit fd8b60
#define TEST_PA_TYPE -123
Packit fd8b60
Packit fd8b60
static krb5_preauthtype pa_types[] = { TEST_PA_TYPE, 0 };
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
test_edata(krb5_context context, krb5_kdc_req *req,
Packit fd8b60
           krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
Packit fd8b60
           krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
Packit fd8b60
           krb5_kdcpreauth_edata_respond_fn respond, void *arg)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret;
Packit fd8b60
    const krb5_keyblock *k = cb->client_keyblock(context, rock);
Packit fd8b60
    krb5_pa_data *pa;
Packit fd8b60
    size_t enclen;
Packit fd8b60
    krb5_enc_data enc;
Packit fd8b60
    krb5_data d;
Packit fd8b60
    char *attr;
Packit fd8b60
Packit fd8b60
    ret = cb->get_string(context, rock, "teststring", &attr);
Packit fd8b60
    assert(!ret);
Packit fd8b60
    if (k != NULL) {
Packit fd8b60
        d = string2data((attr != NULL) ? attr : "no attr");
Packit fd8b60
        ret = krb5_c_encrypt_length(context, k->enctype, d.length, &enclen);
Packit fd8b60
        assert(!ret);
Packit fd8b60
        ret = alloc_data(&enc.ciphertext, enclen);
Packit fd8b60
        assert(!ret);
Packit fd8b60
        ret = krb5_c_encrypt(context, k, 1024, NULL, &d, &enc;;
Packit fd8b60
        assert(!ret);
Packit fd8b60
        pa = make_pa(enc.ciphertext.data, enc.ciphertext.length);
Packit fd8b60
        free(enc.ciphertext.data);
Packit fd8b60
    } else {
Packit fd8b60
        pa = make_pa("no key", 6);
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Exercise setting a cookie information from the edata method. */
Packit fd8b60
    d = string2data("method-data");
Packit fd8b60
    ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);
Packit fd8b60
    assert(!ret);
Packit fd8b60
Packit fd8b60
    cb->free_string(context, rock, attr);
Packit fd8b60
    (*respond)(arg, 0, pa);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
test_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
Packit fd8b60
            krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,
Packit fd8b60
            krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
Packit fd8b60
            krb5_kdcpreauth_moddata moddata,
Packit fd8b60
            krb5_kdcpreauth_verify_respond_fn respond, void *arg)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret;
Packit fd8b60
    krb5_boolean second_round_trip = FALSE, optimistic = FALSE;
Packit fd8b60
    krb5_pa_data **list = NULL;
Packit fd8b60
    krb5_data cookie_data, d;
Packit fd8b60
    char *str, *ind, *toksave = NULL;
Packit fd8b60
    char *attr_err, *attr_2rt, *attr_fail2rt, *attr_failopt;
Packit fd8b60
Packit fd8b60
    ret = cb->get_string(context, rock, "err", &attr_err);
Packit fd8b60
    assert(!ret);
Packit fd8b60
    ret = cb->get_string(context, rock, "2rt", &attr_2rt);
Packit fd8b60
    assert(!ret);
Packit fd8b60
    ret = cb->get_string(context, rock, "fail2rt", &attr_fail2rt);
Packit fd8b60
    assert(!ret);
Packit fd8b60
    ret = cb->get_string(context, rock, "failopt", &attr_failopt);
Packit fd8b60
    assert(!ret);
Packit fd8b60
Packit fd8b60
    /* Check the incoming cookie value. */
Packit fd8b60
    if (!cb->get_cookie(context, rock, TEST_PA_TYPE, &cookie_data)) {
Packit fd8b60
        /* Make sure we are seeing optimistic preauth and not a lost cookie. */
Packit fd8b60
        d = make_data(data->contents, data->length);
Packit fd8b60
        assert(data_eq_string(d, "optimistic"));
Packit fd8b60
        optimistic = TRUE;
Packit fd8b60
    } else if (data_eq_string(cookie_data, "more")) {
Packit fd8b60
        second_round_trip = TRUE;
Packit fd8b60
    } else {
Packit fd8b60
        assert(data_eq_string(cookie_data, "method-data") ||
Packit fd8b60
               data_eq_string(cookie_data, "err"));
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (attr_err != NULL) {
Packit fd8b60
        d = make_data(data->contents, data->length);
Packit fd8b60
        if (data_eq_string(d, "tryagain")) {
Packit fd8b60
            /* Authenticate successfully. */
Packit fd8b60
            enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
Packit fd8b60
        } else {
Packit fd8b60
            d = string2data("err");
Packit fd8b60
            ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);
Packit fd8b60
            assert(!ret);
Packit fd8b60
            ret = KRB5KDC_ERR_ETYPE_NOSUPP;
Packit fd8b60
            list = make_pa_list(attr_err, strlen(attr_err));
Packit fd8b60
        }
Packit fd8b60
    } else if (attr_2rt != NULL && !second_round_trip) {
Packit fd8b60
        d = string2data("more");
Packit fd8b60
        ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);
Packit fd8b60
        assert(!ret);
Packit fd8b60
        ret = KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
Packit fd8b60
        list = make_pa_list(attr_2rt, strlen(attr_2rt));
Packit fd8b60
    } else if ((attr_fail2rt != NULL && second_round_trip) ||
Packit fd8b60
               (attr_failopt != NULL && optimistic)) {
Packit fd8b60
        ret = KRB5KDC_ERR_PREAUTH_FAILED;
Packit fd8b60
    } else {
Packit fd8b60
        /* Parse and assert the indicators. */
Packit fd8b60
        str = k5memdup0(data->contents, data->length, &ret;;
Packit fd8b60
        if (ret)
Packit fd8b60
            abort();
Packit fd8b60
        ind = strtok_r(str, " ", &toksave);
Packit fd8b60
        while (ind != NULL) {
Packit fd8b60
            cb->add_auth_indicator(context, rock, ind);
Packit fd8b60
            ind = strtok_r(NULL, " ", &toksave);
Packit fd8b60
        }
Packit fd8b60
        free(str);
Packit fd8b60
        enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    cb->free_string(context, rock, attr_err);
Packit fd8b60
    cb->free_string(context, rock, attr_2rt);
Packit fd8b60
    cb->free_string(context, rock, attr_fail2rt);
Packit fd8b60
    cb->free_string(context, rock, attr_failopt);
Packit fd8b60
    (*respond)(arg, ret, NULL, list, NULL);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
test_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,
Packit fd8b60
            krb5_kdc_req *request, krb5_kdc_rep *reply,
Packit fd8b60
            krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out,
Packit fd8b60
            krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
Packit fd8b60
            krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
Packit fd8b60
{
Packit fd8b60
    const krb5_keyblock *k = cb->client_keyblock(context, rock);
Packit fd8b60
Packit fd8b60
    assert(k == encrypting_key || k == NULL);
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
kdcpreauth_test_initvt(krb5_context context, int maj_ver,
Packit fd8b60
                             int min_ver, krb5_plugin_vtable vtable);
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
kdcpreauth_test_initvt(krb5_context context, int maj_ver,
Packit fd8b60
                             int min_ver, krb5_plugin_vtable vtable)
Packit fd8b60
{
Packit fd8b60
    krb5_kdcpreauth_vtable vt;
Packit fd8b60
Packit fd8b60
    if (maj_ver != 1)
Packit fd8b60
        return KRB5_PLUGIN_VER_NOTSUPP;
Packit fd8b60
    vt = (krb5_kdcpreauth_vtable)vtable;
Packit fd8b60
    vt->name = "test";
Packit fd8b60
    vt->pa_type_list = pa_types;
Packit fd8b60
    vt->edata = test_edata;
Packit fd8b60
    vt->verify = test_verify;
Packit fd8b60
    vt->return_padata = test_return;
Packit fd8b60
    return 0;
Packit fd8b60
}