/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* tests/gssapi/t_enctypes.c - gss_krb5_set_allowable_enctypes test */
/*
* Copyright (C) 2013 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.
*/
#include "k5-int.h"
#include "common.h"
#include "gssapi_ext.h"
/*
* This test program establishes contexts with the krb5 mech, the default
* initiator name, a specified target name, and the default acceptor name.
* Before the exchange, gss_set_allowable_enctypes is called for the initiator
* and the acceptor cred if requested. If the exchange is successful, the
* resulting contexts are exported with gss_krb5_export_lucid_sec_context,
* checked for mismatches, and the GSS protocol and keys are displayed. Exits
* with status 0 if all operations are successful, or 1 if not.
*
* Usage: ./t_enctypes [-i initenctypes] [-a accenctypes] targetname
*/
static void
usage()
{
errout("Usage: t_enctypes [-i initenctypes] [-a accenctypes] "
"targetname");
}
/* Error out if ikey is not the same as akey. */
static void
check_key_match(gss_krb5_lucid_key_t *ikey, gss_krb5_lucid_key_t *akey)
{
if (ikey->type != akey->type || ikey->length != akey->length ||
memcmp(ikey->data, akey->data, ikey->length) != 0)
errout("Initiator and acceptor keys do not match");
}
/* Display the name of enctype. */
static void
display_enctype(krb5_enctype enctype)
{
char ename[128];
if (krb5_enctype_to_name(enctype, FALSE, ename, sizeof(ename)) == 0)
fputs(ename, stdout);
else
fputs("(unknown)", stdout);
}
int
main(int argc, char *argv[])
{
krb5_error_code ret;
krb5_context kctx = NULL;
krb5_enctype *ienc = NULL, *aenc = NULL, zero = 0;
OM_uint32 minor, major, flags;
gss_name_t tname;
gss_cred_id_t icred = GSS_C_NO_CREDENTIAL, acred = GSS_C_NO_CREDENTIAL;
gss_ctx_id_t ictx, actx;
gss_krb5_lucid_context_v1_t *ilucid, *alucid;
gss_krb5_rfc1964_keydata_t *i1964, *a1964;
gss_krb5_cfx_keydata_t *icfx, *acfx;
gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
unsigned int ssf;
size_t count;
void *lptr;
int c;
ret = krb5_init_context(&kctx);
check_k5err(kctx, "krb5_init_context", ret);
/* Parse arguments. */
while ((c = getopt(argc, argv, "i:a:")) != -1) {
switch (c) {
case 'i':
ret = krb5int_parse_enctype_list(kctx, "", optarg, &zero, &ienc);
check_k5err(kctx, "krb5_parse_enctype_list(initiator)", ret);
break;
case 'a':
ret = krb5int_parse_enctype_list(kctx, "", optarg, &zero, &aenc);
check_k5err(kctx, "krb5_parse_enctype_list(acceptor)", ret);
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
tname = import_name(*argv);
if (ienc != NULL) {
major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE,
&mechset_krb5, GSS_C_INITIATE, &icred, NULL,
NULL);
check_gsserr("gss_acquire_cred(initiator)", major, minor);
for (count = 0; ienc[count]; count++);
major = gss_krb5_set_allowable_enctypes(&minor, icred, count, ienc);
check_gsserr("gss_krb5_set_allowable_enctypes(init)", major, minor);
}
if (aenc != NULL) {
major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE,
&mechset_krb5, GSS_C_ACCEPT, &acred, NULL,
NULL);
check_gsserr("gss_acquire_cred(acceptor)", major, minor);
for (count = 0; aenc[count]; count++);
major = gss_krb5_set_allowable_enctypes(&minor, acred, count, aenc);
check_gsserr("gss_krb5_set_allowable_enctypes(acc)", major, minor);
}
flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG;
establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx,
NULL, NULL, NULL);
/* Query the SSF value and range-check the result. */
major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset);
check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor);
if (bufset->elements[0].length != 4)
errout("SSF buffer has unexpected length");
ssf = load_32_be(bufset->elements[0].value);
if (ssf < 56 || ssf > 256)
errout("SSF value not within acceptable range (56-256)");
(void)gss_release_buffer_set(&minor, &bufset);
/* Export to lucid contexts. */
major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr);
check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor);
ilucid = lptr;
major = gss_krb5_export_lucid_sec_context(&minor, &actx, 1, &lptr);
check_gsserr("gss_export_lucid_sec_context(acceptor)", major, minor);
alucid = lptr;
/* Grab the session keys and make sure they match. */
if (ilucid->protocol != alucid->protocol)
errout("Initiator/acceptor protocol mismatch");
if (ilucid->protocol) {
icfx = &ilucid->cfx_kd;
acfx = &alucid->cfx_kd;
if (icfx->have_acceptor_subkey != acfx->have_acceptor_subkey)
errout("Initiator/acceptor have_acceptor_subkey mismatch");
check_key_match(&icfx->ctx_key, &acfx->ctx_key);
if (icfx->have_acceptor_subkey)
check_key_match(&icfx->acceptor_subkey, &acfx->acceptor_subkey);
fputs("cfx ", stdout);
display_enctype(icfx->ctx_key.type);
if (icfx->have_acceptor_subkey) {
fputs(" ", stdout);
display_enctype(icfx->acceptor_subkey.type);
}
fputs("\n", stdout);
} else {
i1964 = &ilucid->rfc1964_kd;
a1964 = &alucid->rfc1964_kd;
if (i1964->sign_alg != a1964->sign_alg ||
i1964->seal_alg != a1964->seal_alg)
errout("Initiator/acceptor sign or seal alg mismatch");
check_key_match(&i1964->ctx_key, &a1964->ctx_key);
fputs("rfc1964 ", stdout);
display_enctype(i1964->ctx_key.type);
fputs("\n", stdout);
}
krb5_free_context(kctx);
free(ienc);
free(aenc);
(void)gss_release_name(&minor, &tname);
(void)gss_release_cred(&minor, &icred);
(void)gss_release_cred(&minor, &acred);
(void)gss_delete_sec_context(&minor, &ictx, NULL);
(void)gss_delete_sec_context(&minor, &actx, NULL);
(void)gss_krb5_free_lucid_sec_context(&minor, ilucid);
(void)gss_krb5_free_lucid_sec_context(&minor, alucid);
return 0;
}