1178825Sdfr/* 2178825Sdfr * Copyright (c) 2004, PADL Software Pty Ltd. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5178825Sdfr * Redistribution and use in source and binary forms, with or without 6178825Sdfr * modification, are permitted provided that the following conditions 7178825Sdfr * are met: 8178825Sdfr * 9178825Sdfr * 1. Redistributions of source code must retain the above copyright 10178825Sdfr * notice, this list of conditions and the following disclaimer. 11178825Sdfr * 12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13178825Sdfr * notice, this list of conditions and the following disclaimer in the 14178825Sdfr * documentation and/or other materials provided with the distribution. 15178825Sdfr * 16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors 17178825Sdfr * may be used to endorse or promote products derived from this software 18178825Sdfr * without specific prior written permission. 19178825Sdfr * 20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30178825Sdfr * SUCH DAMAGE. 31178825Sdfr */ 32178825Sdfr 33233294Sstas#include "spnego_locl.h" 34178825Sdfr 35178825Sdfr/* 36178825Sdfr * Apparently Microsoft got the OID wrong, and used 37178825Sdfr * 1.2.840.48018.1.2.2 instead. We need both this and 38178825Sdfr * the correct Kerberos OID here in order to deal with 39178825Sdfr * this. Because this is manifest in SPNEGO only I'd 40178825Sdfr * prefer to deal with this here rather than inside the 41178825Sdfr * Kerberos mechanism. 42178825Sdfr */ 43178825Sdfrgss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc = 44233294Sstas {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")}; 45178825Sdfr 46178825Sdfrgss_OID_desc _gss_spnego_krb5_mechanism_oid_desc = 47233294Sstas {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; 48178825Sdfr 49178825Sdfr/* 50178825Sdfr * Allocate a SPNEGO context handle 51178825Sdfr */ 52233294SstasOM_uint32 GSSAPI_CALLCONV 53233294Sstas_gss_spnego_alloc_sec_context (OM_uint32 * minor_status, 54233294Sstas gss_ctx_id_t *context_handle) 55178825Sdfr{ 56178825Sdfr gssspnego_ctx ctx; 57178825Sdfr 58178825Sdfr ctx = calloc(1, sizeof(*ctx)); 59178825Sdfr if (ctx == NULL) { 60178825Sdfr *minor_status = ENOMEM; 61178825Sdfr return GSS_S_FAILURE; 62178825Sdfr } 63178825Sdfr 64178825Sdfr ctx->initiator_mech_types.len = 0; 65178825Sdfr ctx->initiator_mech_types.val = NULL; 66178825Sdfr ctx->preferred_mech_type = GSS_C_NO_OID; 67178825Sdfr ctx->negotiated_mech_type = GSS_C_NO_OID; 68178825Sdfr ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; 69178825Sdfr 70178825Sdfr /* 71178825Sdfr * Cache these so we can return them before returning 72178825Sdfr * GSS_S_COMPLETE, even if the mechanism has itself 73178825Sdfr * completed earlier 74178825Sdfr */ 75178825Sdfr ctx->mech_flags = 0; 76178825Sdfr ctx->mech_time_rec = 0; 77178825Sdfr ctx->mech_src_name = GSS_C_NO_NAME; 78178825Sdfr 79178825Sdfr ctx->open = 0; 80178825Sdfr ctx->local = 0; 81178825Sdfr ctx->require_mic = 0; 82178825Sdfr ctx->verified_mic = 0; 83178825Sdfr 84178825Sdfr HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); 85178825Sdfr 86178825Sdfr *context_handle = (gss_ctx_id_t)ctx; 87178825Sdfr 88178825Sdfr return GSS_S_COMPLETE; 89178825Sdfr} 90178825Sdfr 91178825Sdfr/* 92178825Sdfr * Free a SPNEGO context handle. The caller must have acquired 93178825Sdfr * the lock before this is called. 94178825Sdfr */ 95233294SstasOM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context 96178825Sdfr (OM_uint32 *minor_status, 97178825Sdfr gss_ctx_id_t *context_handle, 98178825Sdfr gss_buffer_t output_token 99178825Sdfr ) 100178825Sdfr{ 101178825Sdfr gssspnego_ctx ctx; 102178825Sdfr OM_uint32 ret, minor; 103178825Sdfr 104178825Sdfr *minor_status = 0; 105178825Sdfr 106178825Sdfr if (context_handle == NULL) { 107178825Sdfr return GSS_S_NO_CONTEXT; 108178825Sdfr } 109178825Sdfr 110178825Sdfr if (output_token != GSS_C_NO_BUFFER) { 111178825Sdfr output_token->length = 0; 112178825Sdfr output_token->value = NULL; 113178825Sdfr } 114178825Sdfr 115178825Sdfr ctx = (gssspnego_ctx)*context_handle; 116178825Sdfr *context_handle = GSS_C_NO_CONTEXT; 117178825Sdfr 118178825Sdfr if (ctx == NULL) { 119178825Sdfr return GSS_S_NO_CONTEXT; 120178825Sdfr } 121178825Sdfr 122178825Sdfr if (ctx->initiator_mech_types.val != NULL) 123178825Sdfr free_MechTypeList(&ctx->initiator_mech_types); 124178825Sdfr 125178825Sdfr gss_release_oid(&minor, &ctx->preferred_mech_type); 126178825Sdfr ctx->negotiated_mech_type = GSS_C_NO_OID; 127178825Sdfr 128178825Sdfr gss_release_name(&minor, &ctx->target_name); 129178825Sdfr gss_release_name(&minor, &ctx->mech_src_name); 130178825Sdfr 131178825Sdfr if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) { 132178825Sdfr ret = gss_delete_sec_context(minor_status, 133178825Sdfr &ctx->negotiated_ctx_id, 134178825Sdfr output_token); 135178825Sdfr ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; 136178825Sdfr } else { 137178825Sdfr ret = GSS_S_COMPLETE; 138178825Sdfr } 139178825Sdfr 140178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 141178825Sdfr HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 142178825Sdfr 143178825Sdfr free(ctx); 144178825Sdfr 145178825Sdfr return ret; 146178825Sdfr} 147178825Sdfr 148178825Sdfr/* 149178825Sdfr * For compatability with the Windows SPNEGO implementation, the 150178825Sdfr * default is to ignore the mechListMIC unless CFX is used and 151178825Sdfr * a non-preferred mechanism was negotiated 152178825Sdfr */ 153178825Sdfr 154233294SstasOM_uint32 GSSAPI_CALLCONV 155178825Sdfr_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, 156178825Sdfr gssspnego_ctx ctx, 157178825Sdfr int *require_mic) 158178825Sdfr{ 159178825Sdfr gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET; 160178825Sdfr OM_uint32 minor; 161178825Sdfr 162178825Sdfr *minor_status = 0; 163178825Sdfr *require_mic = 0; 164178825Sdfr 165178825Sdfr if (ctx == NULL) { 166178825Sdfr return GSS_S_COMPLETE; 167178825Sdfr } 168178825Sdfr 169178825Sdfr if (ctx->require_mic) { 170178825Sdfr /* Acceptor requested it: mandatory to honour */ 171178825Sdfr *require_mic = 1; 172178825Sdfr return GSS_S_COMPLETE; 173178825Sdfr } 174178825Sdfr 175178825Sdfr /* 176178825Sdfr * Check whether peer indicated implicit support for updated SPNEGO 177178825Sdfr * (eg. in the Kerberos case by using CFX) 178178825Sdfr */ 179178825Sdfr if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id, 180178825Sdfr GSS_C_PEER_HAS_UPDATED_SPNEGO, 181178825Sdfr &buffer_set) == GSS_S_COMPLETE) { 182178825Sdfr *require_mic = 1; 183178825Sdfr gss_release_buffer_set(&minor, &buffer_set); 184178825Sdfr } 185178825Sdfr 186178825Sdfr /* Safe-to-omit MIC rules follow */ 187178825Sdfr if (*require_mic) { 188178825Sdfr if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) { 189178825Sdfr *require_mic = 0; 190178825Sdfr } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) && 191178825Sdfr gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) { 192178825Sdfr *require_mic = 0; 193178825Sdfr } 194178825Sdfr } 195178825Sdfr 196178825Sdfr return GSS_S_COMPLETE; 197178825Sdfr} 198178825Sdfr 199178825Sdfrstatic int 200178825Sdfradd_mech_type(gss_OID mech_type, 201178825Sdfr int includeMSCompatOID, 202178825Sdfr MechTypeList *mechtypelist) 203178825Sdfr{ 204178825Sdfr MechType mech; 205178825Sdfr int ret; 206178825Sdfr 207178825Sdfr if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) 208178825Sdfr return 0; 209178825Sdfr 210178825Sdfr if (includeMSCompatOID && 211178825Sdfr gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) { 212178825Sdfr ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements, 213178825Sdfr _gss_spnego_mskrb_mechanism_oid_desc.length, 214178825Sdfr &mech, 215178825Sdfr NULL); 216178825Sdfr if (ret) 217178825Sdfr return ret; 218178825Sdfr ret = add_MechTypeList(mechtypelist, &mech); 219178825Sdfr free_MechType(&mech); 220178825Sdfr if (ret) 221178825Sdfr return ret; 222178825Sdfr } 223178825Sdfr ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL); 224178825Sdfr if (ret) 225178825Sdfr return ret; 226178825Sdfr ret = add_MechTypeList(mechtypelist, &mech); 227178825Sdfr free_MechType(&mech); 228178825Sdfr return ret; 229178825Sdfr} 230178825Sdfr 231178825Sdfr 232233294SstasOM_uint32 GSSAPI_CALLCONV 233178825Sdfr_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, 234178825Sdfr gss_name_t target_name, 235178825Sdfr OM_uint32 (*func)(gss_name_t, gss_OID), 236178825Sdfr int includeMSCompatOID, 237233294Sstas const gss_cred_id_t cred_handle, 238178825Sdfr MechTypeList *mechtypelist, 239178825Sdfr gss_OID *preferred_mech) 240178825Sdfr{ 241178825Sdfr gss_OID_set supported_mechs = GSS_C_NO_OID_SET; 242178825Sdfr gss_OID first_mech = GSS_C_NO_OID; 243178825Sdfr OM_uint32 ret; 244233294Sstas size_t i; 245178825Sdfr 246178825Sdfr mechtypelist->len = 0; 247178825Sdfr mechtypelist->val = NULL; 248178825Sdfr 249233294Sstas if (cred_handle) { 250178825Sdfr ret = gss_inquire_cred(minor_status, 251233294Sstas cred_handle, 252178825Sdfr NULL, 253178825Sdfr NULL, 254178825Sdfr NULL, 255178825Sdfr &supported_mechs); 256178825Sdfr } else { 257178825Sdfr ret = gss_indicate_mechs(minor_status, &supported_mechs); 258178825Sdfr } 259178825Sdfr 260178825Sdfr if (ret != GSS_S_COMPLETE) { 261178825Sdfr return ret; 262178825Sdfr } 263178825Sdfr 264178825Sdfr if (supported_mechs->count == 0) { 265178825Sdfr *minor_status = ENOENT; 266178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 267178825Sdfr return GSS_S_FAILURE; 268178825Sdfr } 269178825Sdfr 270178825Sdfr ret = (*func)(target_name, GSS_KRB5_MECHANISM); 271178825Sdfr if (ret == GSS_S_COMPLETE) { 272178825Sdfr ret = add_mech_type(GSS_KRB5_MECHANISM, 273178825Sdfr includeMSCompatOID, 274178825Sdfr mechtypelist); 275178825Sdfr if (!GSS_ERROR(ret)) 276178825Sdfr first_mech = GSS_KRB5_MECHANISM; 277178825Sdfr } 278178825Sdfr ret = GSS_S_COMPLETE; 279178825Sdfr 280178825Sdfr for (i = 0; i < supported_mechs->count; i++) { 281178825Sdfr OM_uint32 subret; 282178825Sdfr if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM)) 283178825Sdfr continue; 284178825Sdfr if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM)) 285178825Sdfr continue; 286178825Sdfr 287178825Sdfr subret = (*func)(target_name, &supported_mechs->elements[i]); 288178825Sdfr if (subret != GSS_S_COMPLETE) 289178825Sdfr continue; 290178825Sdfr 291178825Sdfr ret = add_mech_type(&supported_mechs->elements[i], 292178825Sdfr includeMSCompatOID, 293178825Sdfr mechtypelist); 294178825Sdfr if (ret != 0) { 295178825Sdfr *minor_status = ret; 296178825Sdfr ret = GSS_S_FAILURE; 297178825Sdfr break; 298178825Sdfr } 299178825Sdfr if (first_mech == GSS_C_NO_OID) 300178825Sdfr first_mech = &supported_mechs->elements[i]; 301178825Sdfr } 302178825Sdfr 303178825Sdfr if (mechtypelist->len == 0) { 304178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 305178825Sdfr *minor_status = 0; 306178825Sdfr return GSS_S_BAD_MECH; 307178825Sdfr } 308178825Sdfr 309178825Sdfr if (preferred_mech != NULL) { 310178825Sdfr ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech); 311178825Sdfr if (ret != GSS_S_COMPLETE) 312178825Sdfr free_MechTypeList(mechtypelist); 313178825Sdfr } 314178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 315178825Sdfr 316178825Sdfr return ret; 317178825Sdfr} 318