From c2e3c5b66e9f2a7148b635761ee9911a8579c3a8 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Fri, 7 Jan 2022 15:55:15 -0600 Subject: [PATCH] gss: Add way to set authenticator authz-data Now we can set Authenticator authorization-data with gss_set_name_attribute(). --- lib/asn1/krb5.asn1 | 3 +- lib/gssapi/Makefile.am | 2 +- lib/gssapi/krb5/init_sec_context.c | 39 +++++++++++++++++++ lib/gssapi/krb5/name_attrs.c | 60 +++++++++++++++++++++++++++++- lib/gssapi/test_context.c | 46 +++++++++++++++++++++++ lib/krb5/libkrb5-exports.def.in | 2 + lib/krb5/version-script.map | 2 + tests/gss/check-context.in | 8 ++++ 8 files changed, 159 insertions(+), 3 deletions(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index f442d3739..639ec5af2 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -476,10 +476,11 @@ PrincipalNameAttrs ::= SEQUENCE { -- True if the PAC was verified pac-verified [5] BOOLEAN, -- True if any AD-KDC-ISSUEDs in the Ticket were validated - kdc-issued-verified [6] BOOLEAN + kdc-issued-verified [6] BOOLEAN, -- TODO: Add requested attributes, for gss_set_name_attribute(), which -- should cause corresponding authz-data elements to be added to -- any TGS-REQ or to the AP-REQ's Authenticator as appropriate. + want-ad [7] AuthorizationData OPTIONAL } -- This is our type for exported composite name tokens for GSS [RFC6680]. -- It's the same as Principal (below) as decorated with (see krb5.opt file and diff --git a/lib/gssapi/Makefile.am b/lib/gssapi/Makefile.am index 8200037d7..ea26da2dc 100644 --- a/lib/gssapi/Makefile.am +++ b/lib/gssapi/Makefile.am @@ -385,7 +385,7 @@ LDADD = libgssapi.la \ $(LIB_roken) test_names_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la -test_context_LDADD = $(LDADD) $(top_builddir)/lib/wind/libwind.la +test_context_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la $(top_builddir)/lib/wind/libwind.la # gss diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 11e40f774..d82fef8d3 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -33,6 +33,12 @@ #include "gsskrb5_locl.h" +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *, + krb5_context, + krb5_auth_context, + gss_const_name_t); + /* * copy the addresses from `input_chan_bindings' (if any) to * the auth context `ac' @@ -418,6 +424,11 @@ init_auth if (ret) goto failure; + ret = gsskrb5_set_authorization_data(minor_status, context, + ctx->auth_context, name); + if (ret) + goto failure; + ctx->endtime = ctx->kcred->times.endtime; ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); @@ -977,3 +988,31 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context return ret; } + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *minor_status, + krb5_context context, + krb5_auth_context auth_context, + gss_const_name_t gn) +{ + const CompositePrincipal *name = (const void *)gn; + AuthorizationData *ad; + krb5_error_code kret = 0; + size_t i; + + if (name->nameattrs == NULL || name->nameattrs->want_ad == NULL) + return GSS_S_COMPLETE; + + ad = name->nameattrs->want_ad; + for (i = 0; kret == 0 && i < ad->len; i++) { + kret = krb5_auth_con_add_AuthorizationData(context, auth_context, + ad->val[0].ad_type, + &ad->val[0].ad_data); + } + + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/krb5/name_attrs.c b/lib/gssapi/krb5/name_attrs.c index 8c7df1647..e6039906b 100644 --- a/lib/gssapi/krb5/name_attrs.c +++ b/lib/gssapi/krb5/name_attrs.c @@ -172,6 +172,7 @@ static get_name_attr_f get_pac; static get_name_attr_f get_authz_data; static get_name_attr_f get_ticket_authz_data; static get_name_attr_f get_authenticator_authz_data; +static set_name_attr_f set_authenticator_authz_data; static get_name_attr_f get_transited; static get_name_attr_f get_canonical_name; @@ -209,7 +210,8 @@ static struct krb5_name_attrs { { NB("ticket-authz-data"), get_ticket_authz_data, NULL, NULL, 1, 1 }, { NB("authenticator-authz-data"), - get_authenticator_authz_data, NULL, NULL, 1, 1 }, + get_authenticator_authz_data, + set_authenticator_authz_data, NULL, 1, 1 }, { NB("authz-data"), get_authz_data, NULL, NULL, 1, 1 }, { NB("transit-path"), get_transited, NULL, NULL, 1, 1 }, { NB("canonical-name"), get_canonical_name, NULL, NULL, 1, 1 }, @@ -922,6 +924,62 @@ get_authenticator_authz_data(OM_uint32 *minor_status, return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; } +static OM_uint32 +set_authenticator_authz_data(OM_uint32 *minor_status, + CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int complete, + gss_buffer_t value) +{ + AuthorizationDataElement e; + krb5_error_code kret; + size_t sz; + + if (!value) + return GSS_S_CALL_INACCESSIBLE_READ; + if (frag->length && + !ATTR_EQ(frag, "if-relevant")) + return GSS_S_UNAVAILABLE; + + if ((name->nameattrs == NULL && + (name->nameattrs = calloc(1, sizeof(*name->nameattrs))) == NULL) || + (name->nameattrs->want_ad == NULL && + (name->nameattrs->want_ad = + calloc(1, sizeof(*name->nameattrs->want_ad))) == NULL)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memset(&e, 0, sizeof(e)); + kret = decode_AuthorizationDataElement(value->value, value->length, &e, + &sz); + if (kret == 0) { + if (frag->length) { + AuthorizationData ir; + + ir.len = 0; + ir.val = NULL; + kret = add_AuthorizationData(&ir, &e); + free_AuthorizationDataElement(&e); + if (kret == 0) { + e.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + ASN1_MALLOC_ENCODE(AuthorizationData, e.ad_data.data, + e.ad_data.length, &ir, &sz, kret); + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + } + free_AuthorizationData(&ir); + } else { + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + free_AuthorizationDataElement(&e); + } + } + + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + static OM_uint32 get_transited(OM_uint32 *minor_status, const CompositePrincipal *name, diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index 37cc41ac2..f96c48fcd 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -56,6 +56,7 @@ static char *localname_string; static char *client_name; static char *client_password; static char *localname_string; +static char *on_behalf_of_string; static int dns_canon_flag = -1; static int mutual_auth_flag = 0; static int dce_style_flag = 0; @@ -294,6 +295,31 @@ loop(gss_OID mechoid, if (GSS_ERROR(maj_stat)) err(1, "import name creds failed with: %d", maj_stat); + if (on_behalf_of_string) { + AuthorizationDataElement e; + gss_buffer_desc attr, value; + int32_t kret; + size_t sz; + + memset(&e, 0, sizeof(e)); + e.ad_type = KRB5_AUTHDATA_ON_BEHALF_OF; + e.ad_data.length = strlen(on_behalf_of_string); + e.ad_data.data = on_behalf_of_string; + ASN1_MALLOC_ENCODE(AuthorizationDataElement, value.value, value.length, + &e, &sz, kret); + if (kret) + errx(1, "Could not encode AD-ON-BEHALF-OF AuthorizationDataElement"); + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data") - 1; + maj_stat = gss_set_name_attribute(&min_stat, gss_target_name, 1, &attr, + &value); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_set_name_attribute() failed with: %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + } + input_token.length = 0; input_token.value = NULL; @@ -457,6 +483,24 @@ loop(gss_OID mechoid, errx(1, "mech mismatch"); *actual_mech = actual_mech_server; + if (on_behalf_of_string) { + gss_buffer_desc attr, value; + + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580") - 1; + maj_stat = gss_get_name_attribute(&min_stat, src_name, &attr, NULL, + NULL, &value, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_get_name_attribute(authz-data#580) failed with %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + + if (value.length != strlen(on_behalf_of_string) || + strncmp(value.value, on_behalf_of_string, + strlen(on_behalf_of_string)) != 0) + errx(1, "AD-ON-BEHALF-OF did not match"); + } if (localname_string) { gss_buffer_desc lname; @@ -865,6 +909,8 @@ static struct getargs args[] = { {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL }, {"max-loops", 0, arg_integer, &max_loops, "time", NULL }, {"token-split", 0, arg_integer, &token_split, "bytes", NULL }, + {"on-behalf-of", 0, arg_string, &on_behalf_of_string, "principal", + "send authenticator authz-data AD-ON-BEHALF-OF" }, {"version", 0, arg_flag, &version_flag, "print version", NULL }, {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, {"help", 0, arg_flag, &help_flag, NULL, NULL } diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index cf46c74d4..2dbc781a3 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -23,6 +23,8 @@ EXPORTS krb5_appdefault_time krb5_append_addresses krb5_auth_con_addflags + krb5_auth_con_add_AuthorizationData + krb5_auth_con_add_AuthorizationDataIfRelevant krb5_auth_con_free krb5_auth_con_genaddrs krb5_auth_con_generatelocalsubkey diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index a389d1b64..7db0d6f5e 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -24,6 +24,8 @@ HEIMDAL_KRB5_2.0 { krb5_appdefault_time; krb5_append_addresses; krb5_auth_con_addflags; + krb5_auth_con_add_AuthorizationData; + krb5_auth_con_add_AuthorizationDataIfRelevant; krb5_auth_con_free; krb5_auth_con_genaddrs; krb5_auth_con_generatelocalsubkey; diff --git a/tests/gss/check-context.in b/tests/gss/check-context.in index 42ea15eec..b2e17427e 100644 --- a/tests/gss/check-context.in +++ b/tests/gss/check-context.in @@ -245,6 +245,14 @@ for mech in krb5 krb5iov spnego spnegoiov; do { eval "$testfailed"; } done +echo "======test authz-data (krb5)" +${context} --mech-type=krb5 \ + --mutual \ + --wrapunwrap \ + --on-behalf-of=foo@BAR.TEST.H5L.SE \ + --name-type=hostbased-service host@lucid.test.h5l.se || + { eval "$testfailed"; } + echo "======dce-style" for mech in krb5 krb5iov spnego; do iov=""