From 6e20892369a9fafa09294529fb4d331e4fcbb97a Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Tue, 9 Jul 2024 15:14:03 -0400 Subject: [PATCH] Add acceptor-side IAKERB realm discovery draft-ietf-kitten-iakerb-03 section 3.1 specifies a way for the initiator to query the acceptor's realm. Implement this facility in the IAKERB acceptor. ticket: 9133 (new) --- .gitignore | 1 + src/lib/gssapi/krb5/iakerb.c | 66 ++++++++++++++++++++++++--- src/tests/gssapi/Makefile.in | 32 +++++++------ src/tests/gssapi/t_gssapi.py | 2 + src/tests/gssapi/t_iakerb.c | 88 ++++++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 src/tests/gssapi/t_iakerb.c diff --git a/.gitignore b/.gitignore index db1478fed9..90bfa0e206 100644 --- a/.gitignore +++ b/.gitignore @@ -463,6 +463,7 @@ local.properties /src/tests/gssapi/t_export_cred /src/tests/gssapi/t_export_name /src/tests/gssapi/t_gssexts +/src/tests/gssapi/t_iakerb /src/tests/gssapi/t_imp_cred /src/tests/gssapi/t_imp_name /src/tests/gssapi/t_invalid diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c index 9e8bc05dab..69c3445d6b 100644 --- a/src/lib/gssapi/krb5/iakerb.c +++ b/src/lib/gssapi/krb5/iakerb.c @@ -283,6 +283,53 @@ cleanup: return code; } +/* Generate a response to a realm discovery request. */ +static krb5_error_code +iakerb_acceptor_realm(iakerb_ctx_id_t ctx, gss_cred_id_t verifier_cred, + gss_buffer_t output_token) +{ + krb5_error_code ret; + OM_uint32 dummy; + krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)verifier_cred; + krb5_data realm = empty_data(), reply = empty_data(); + krb5_error error = { 0 }; + char *defrealm = NULL; + + /* Get the acceptor realm from the verifier cred if we can; otherwise try + * to use the default realm. */ + if (cred != NULL && cred->name != NULL && + cred->name->princ->realm.length > 0) { + realm = cred->name->princ->realm; + } else { + ret = krb5_get_default_realm(ctx->k5c, &defrealm); + if (ret) { + /* Generate an error reply if there is no default realm. */ + error.error = KRB_ERR_GENERIC; + ret = krb5_mk_error(ctx->k5c, &error, &reply); + if (ret) + goto cleanup; + } else { + realm = string2data(defrealm); + } + } + + ret = iakerb_make_token(ctx, &realm, NULL, &reply, output_token); + if (ret) + goto cleanup; + ret = iakerb_save_token(ctx, output_token); + if (ret) + goto cleanup; + + ctx->count++; + +cleanup: + if (ret) + gss_release_buffer(&dummy, output_token); + krb5_free_default_realm(ctx->k5c, defrealm); + krb5_free_data_contents(ctx->k5c, &reply); + return ret; +} + /* * Parse the IAKERB token in input_token and send the contained KDC * request to the KDC for the realm. @@ -290,7 +337,7 @@ cleanup: * Wrap the KDC reply in output_token. */ static krb5_error_code -iakerb_acceptor_step(iakerb_ctx_id_t ctx, +iakerb_acceptor_step(iakerb_ctx_id_t ctx, gss_cred_id_t verifier_cred, const gss_buffer_t input_token, gss_buffer_t output_token) { @@ -313,15 +360,19 @@ iakerb_acceptor_step(iakerb_ctx_id_t ctx, if (code != 0) goto cleanup; - if (realm.length == 0 || request.length == 0) { - code = KRB5_BAD_MSIZE; - goto cleanup; - } - code = iakerb_save_token(ctx, input_token); if (code != 0) goto cleanup; + if (realm.length == 0 && request.length == 0) { + /* This is a realm discovery request. */ + code = iakerb_acceptor_realm(ctx, verifier_cred, output_token); + goto cleanup; + } else if (realm.length == 0 || request.length == 0) { + code = KRB5_BAD_MSIZE; + goto cleanup; + } + for (tcp_only = 0; tcp_only <= 1; tcp_only++) { use_primary = 0; code = krb5_sendto_kdc(ctx->k5c, &request, &realm, @@ -770,7 +821,8 @@ iakerb_gss_accept_sec_context(OM_uint32 *minor_status, major_status = GSS_S_DEFECTIVE_TOKEN; goto cleanup; } - code = iakerb_acceptor_step(ctx, input_token, output_token); + code = iakerb_acceptor_step(ctx, verifier_cred_handle, input_token, + output_token); if (code == (OM_uint32)KRB5_BAD_MSIZE) major_status = GSS_S_DEFECTIVE_TOKEN; if (code != 0) diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in index ee65a65f34..97a6ac3f3f 100644 --- a/src/tests/gssapi/Makefile.in +++ b/src/tests/gssapi/Makefile.in @@ -13,9 +13,9 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \ $(srcdir)/t_bindings.c $(srcdir)/t_ccselect.c $(srcdir)/t_ciflags.c \ $(srcdir)/t_context.c $(srcdir)/t_credstore.c $(srcdir)/t_enctypes.c \ $(srcdir)/t_err.c $(srcdir)/t_export_cred.c $(srcdir)/t_export_name.c \ - $(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \ - $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \ - $(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \ + $(srcdir)/t_gssexts.c $(srcdir)/t_iakerb.c $(srcdir)/t_imp_cred.c \ + $(srcdir)/t_imp_name.c $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c \ + $(srcdir)/t_inq_ctx.c $(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \ $(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \ $(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \ $(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \ @@ -24,20 +24,20 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \ OBJS= ccinit.o ccrefresh.o common.o reload.o t_accname.o t_add_cred.o \ t_bindings.o t_ccselect.o t_ciflags.o t_context.o t_credstore.o \ t_enctypes.o t_err.o t_export_cred.o t_export_name.o t_gssexts.o \ - t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o t_inq_ctx.o \ - t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o t_oid.o \ - t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \ - t_spnego.o t_srcattrs.o t_store_cred.o + t_iakerb.o t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o \ + t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o \ + t_oid.o t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \ + t_spnego.o t_srcattrs.o t_store_cred.o t_iakerb.o COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS) all: ccinit ccrefresh reload t_accname t_add_cred t_bindings t_ccselect \ t_ciflags t_context t_credstore t_enctypes t_err t_export_cred \ - t_export_name t_gssexts t_imp_cred t_imp_name t_invalid t_inq_cred \ - t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_namingexts t_oid \ - t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs \ - t_store_cred + t_export_name t_gssexts t_iakerb t_imp_cred t_imp_name t_invalid \ + t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_namingexts \ + t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego \ + t_srcattrs t_store_cred check-unix: t_invalid t_oid t_prf t_imp_name reload $(RUN_TEST) ./t_invalid @@ -93,6 +93,8 @@ t_export_name: t_export_name.o $(COMMON_DEPS) $(CC_LINK) -o $@ t_export_name.o $(COMMON_LIBS) t_gssexts: t_gssexts.o $(COMMON_DEPS) $(CC_LINK) -o $@ t_gssexts.o $(COMMON_LIBS) +t_iakerb: t_iakerb.o $(COMMON_DEPS) + $(CC_LINK) -o $@ t_iakerb.o $(COMMON_LIBS) t_imp_cred: t_imp_cred.o $(COMMON_DEPS) $(CC_LINK) -o $@ t_imp_cred.o $(COMMON_LIBS) t_imp_name: t_imp_name.o $(COMMON_DEPS) @@ -133,7 +135,7 @@ t_store_cred: t_store_cred.o $(COMMON_DEPS) clean: $(RM) ccinit ccrefresh reload t_accname t_add_cred t_bindings $(RM) t_ccselect t_ciflags t_context t_credstore t_enctypes t_err - $(RM) t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name - $(RM) t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime - $(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 - $(RM) t_saslname t_spnego t_srcattrs t_store_cred + $(RM) t_export_cred t_export_name t_gssexts t_iakerb t_imp_cred + $(RM) t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov + $(RM) t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u + $(RM) t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs t_store_cred diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py index 5f093a198c..e1ed571fdd 100755 --- a/src/tests/gssapi/t_gssapi.py +++ b/src/tests/gssapi/t_gssapi.py @@ -13,6 +13,8 @@ realm = K5Realm() # Test gss_add_cred(). realm.run(['./t_add_cred']) +realm.run(['./t_iakerb']) + ### Test acceptor name behavior. # Create some host-based principals and put most of them into the diff --git a/src/tests/gssapi/t_iakerb.c b/src/tests/gssapi/t_iakerb.c new file mode 100644 index 0000000000..a81b526e73 --- /dev/null +++ b/src/tests/gssapi/t_iakerb.c @@ -0,0 +1,88 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* tests/gssapi/t_iakerb.c - IAKERB tests */ +/* + * Copyright (C) 2024 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 +#include +#include +#include "common.h" + +static uint8_t +realm_query[] = { + /* ASN.1 wrapper for IAKERB mech */ + 0x60, 0x10, + 0x06, 0x06, 0x2B, 0x06, 0x01, 0x05, 0x02, 0x05, + /* IAKERB_PROXY token type */ + 0x05, 0x01, + /* IAKERB-HEADER with empty target-realm */ + 0x30, 0x04, + 0xA1, 0x02, 0x0C, 0x00 +}; + +static uint8_t +realm_response[] = { + /* ASN.1 wrapper for IAKERB mech */ + 0x60, 0x1B, + 0x06, 0x06, 0x2B, 0x06, 0x01, 0x05, 0x02, 0x05, + /* IAKERB_PROXY token type */ + 0x05, 0x01, + /* IAKERB-HEADER with configured realm */ + 0x30, 0x0F, + 0xA1, 0x0D, 0x0C, 0x0B, + 'K', 'R', 'B', 'T', 'E', 'S', 'T', '.', 'C', 'O', 'M' +}; + +int +main(void) +{ + OM_uint32 major, minor; + gss_cred_id_t cred; + gss_buffer_desc in, out; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + + major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, &mechset_iakerb, + GSS_C_ACCEPT, &cred, NULL, NULL); + check_gsserr("gss_acquire_cred", major, minor); + + in.value = realm_query; + in.length = sizeof(realm_query); + major = gss_accept_sec_context(&minor, &ctx, cred, &in, + GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, &out, + NULL, NULL, NULL); + check_gsserr("gss_accept_sec_context", major, minor); + assert(out.length == sizeof(realm_response)); + assert(memcmp(out.value, realm_response, out.length) == 0); + + gss_release_buffer(&minor, &out); + gss_delete_sec_context(&minor, &ctx, NULL); + gss_release_cred(&minor, &cred); + return 0; +} -- 2.47.2