From c8e9758db1d8a536a1404187b5911a96f7cdbea3 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 21 Aug 2015 18:48:06 -0400 Subject: [PATCH] Update SPNEGO hintName value to current spec [MS-SPNG] currently specifies that the hintName field of NegHints should contain "not_defined_in_RFC4178@please_ignore". Heimdal implements this behavior, but we instead try to include a display name. Implement the currently specified behavior, and add a test to t_spnego.c to verify that the expected hint token is generated. Further cleanup is possible; the negHints encoding is now constant (so it does not need to be generated dynamically), and we could avoid abusing the mechListMIC parameter of make_spnego_tokenInit_msg() to transport it. ticket: 8236 (new) --- src/lib/gssapi/spnego/spnego_mech.c | 98 ++++------------------------- src/tests/gssapi/t_spnego.c | 38 +++++++++++ 2 files changed, 49 insertions(+), 87 deletions(-) diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index f3d5f092e4..ef76e1f1bd 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -191,7 +191,7 @@ static const gss_OID_set_desc spnego_oidsets[] = { }; const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0; -static int make_NegHints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *); +static int make_NegHints(OM_uint32 *, gss_buffer_t *); static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int); static OM_uint32 acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, spnego_gss_cred_id_t, @@ -1185,97 +1185,24 @@ put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token, #define HOST_PREFIX "host@" #define HOST_PREFIX_LEN (sizeof(HOST_PREFIX) - 1) +/* Encode the dummy hintname string (as specified in [MS-SPNG]) into a + * DER-encoded [0] tagged GeneralString, and place the result in *outbuf. */ static int -make_NegHints(OM_uint32 *minor_status, - spnego_gss_cred_id_t spcred, gss_buffer_t *outbuf) +make_NegHints(OM_uint32 *minor_status, gss_buffer_t *outbuf) { - gss_buffer_desc hintNameBuf; - gss_name_t hintName = GSS_C_NO_NAME; - gss_name_t hintKerberosName; - gss_OID hintNameType; OM_uint32 major_status; - OM_uint32 minor; unsigned int tlen = 0; unsigned int hintNameSize = 0; unsigned char *ptr; unsigned char *t; + const char *hintname = "not_defined_in_RFC4178@please_ignore"; + const size_t hintname_len = strlen(hintname); *outbuf = GSS_C_NO_BUFFER; - - if (spcred != NULL) { - major_status = gss_inquire_cred(minor_status, - spcred->mcred, - &hintName, - NULL, - NULL, - NULL); - if (major_status != GSS_S_COMPLETE) - return (major_status); - } - - if (hintName == GSS_C_NO_NAME) { - krb5_error_code code; - krb5int_access kaccess; - char hostname[HOST_PREFIX_LEN + MAXHOSTNAMELEN + 1] = HOST_PREFIX; - - code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); - if (code != 0) { - *minor_status = code; - return (GSS_S_FAILURE); - } - - /* this breaks mutual authentication but Samba relies on it */ - code = (*kaccess.clean_hostname)(NULL, NULL, - &hostname[HOST_PREFIX_LEN], - MAXHOSTNAMELEN); - if (code != 0) { - *minor_status = code; - return (GSS_S_FAILURE); - } - - hintNameBuf.value = hostname; - hintNameBuf.length = strlen(hostname); - - major_status = gss_import_name(minor_status, - &hintNameBuf, - GSS_C_NT_HOSTBASED_SERVICE, - &hintName); - if (major_status != GSS_S_COMPLETE) { - return (major_status); - } - } - - hintNameBuf.value = NULL; - hintNameBuf.length = 0; - - major_status = gss_canonicalize_name(minor_status, - hintName, - (gss_OID)&gss_mech_krb5_oid, - &hintKerberosName); - if (major_status != GSS_S_COMPLETE) { - gss_release_name(&minor, &hintName); - return (major_status); - } - gss_release_name(&minor, &hintName); - - major_status = gss_display_name(minor_status, - hintKerberosName, - &hintNameBuf, - &hintNameType); - if (major_status != GSS_S_COMPLETE) { - gss_release_name(&minor, &hintName); - return (major_status); - } - gss_release_name(&minor, &hintKerberosName); - - /* - * Now encode the name hint into a NegHints ASN.1 type - */ major_status = GSS_S_FAILURE; /* Length of DER encoded GeneralString */ - tlen = 1 + gssint_der_length_size(hintNameBuf.length) + - hintNameBuf.length; + tlen = 1 + gssint_der_length_size(hintname_len) + hintname_len; hintNameSize = tlen; /* Length of DER encoded hintName */ @@ -1295,12 +1222,11 @@ make_NegHints(OM_uint32 *minor_status, goto errout; *ptr++ = GENERAL_STRING; - if (gssint_put_der_length(hintNameBuf.length, - &ptr, tlen - (int)(ptr-t))) + if (gssint_put_der_length(hintname_len, &ptr, tlen - (int)(ptr-t))) goto errout; - memcpy(ptr, hintNameBuf.value, hintNameBuf.length); - ptr += hintNameBuf.length; + memcpy(ptr, hintname, hintname_len); + ptr += hintname_len; *outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc)); if (*outbuf == NULL) { @@ -1320,8 +1246,6 @@ errout: free(t); } - gss_release_buffer(&minor, &hintNameBuf); - return (major_status); } @@ -1357,7 +1281,7 @@ acc_ctx_hints(OM_uint32 *minor_status, if (ret != GSS_S_COMPLETE) goto cleanup; - ret = make_NegHints(minor_status, spcred, mechListMIC); + ret = make_NegHints(minor_status, mechListMIC); if (ret != GSS_S_COMPLETE) goto cleanup; diff --git a/src/tests/gssapi/t_spnego.c b/src/tests/gssapi/t_spnego.c index 80df1bf655..2483228b1b 100644 --- a/src/tests/gssapi/t_spnego.c +++ b/src/tests/gssapi/t_spnego.c @@ -192,6 +192,42 @@ test_mskrb_oid(gss_name_t tname, gss_cred_id_t acred) free(stok.value); } +/* Check that we return a compatibility NegTokenInit2 message containing + * NegHints for an empty initiator token. */ +static void +test_neghints() +{ + OM_uint32 major, minor; + gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok; + gss_ctx_id_t actx = GSS_C_NO_CONTEXT; + const char *expected = + /* RFC 2743 token framing: [APPLICATION 0] IMPLICIT SEQUENCE followed + * by OBJECT IDENTIFIER and the SPNEGO OID */ + "\x60\x47\x06\x06" "\x2B\x06\x01\x05\x05\x02" + /* [0] SEQUENCE for the NegotiationToken negtokenInit choice */ + "\xA0\x3D\x30\x3B" + /* [0] MechTypeList containing the krb5 OID */ + "\xA0\x0D\x30\x0B\x06\x09" "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02" + /* [3] NegHints containing [0] GeneralString containing the dummy + * hintName string defined in [MS-SPNG] */ + "\xA3\x2A\x30\x28\xA0\x26\x1B\x24" + "not_defined_in_RFC4178@please_ignore"; + + /* Produce a hint token. */ + major = gss_accept_sec_context(&minor, &actx, GSS_C_NO_CREDENTIAL, &itok, + GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, + &atok, NULL, NULL, NULL); + check_gsserr("gss_accept_sec_context(neghints)", major, minor); + + /* Verify it against the expected contents, which are fixed as long as we + * only list the krb5 mech in the token. */ + assert(atok.length == strlen(expected)); + assert(memcmp(atok.value, expected, atok.length) == 0); + + (void)gss_release_buffer(&minor, &atok); + (void)gss_delete_sec_context(&minor, &actx, NULL); +} + int main(int argc, char *argv[]) { @@ -264,6 +300,8 @@ main(int argc, char *argv[]) test_mskrb_oid(target_name, verifier_cred_handle); test_mskrb_oid(target_name, GSS_C_NO_CREDENTIAL); + test_neghints(); + (void)gss_delete_sec_context(&minor, &initiator_context, NULL); (void)gss_delete_sec_context(&minor, &acceptor_context, NULL); (void)gss_release_name(&minor, &source_name); -- 2.47.2