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 33178825Sdfr#include "spnego/spnego_locl.h" 34178825Sdfr 35178825SdfrRCSID("$Id: compat.c 21866 2007-08-08 11:31:29Z lha $"); 36178825Sdfr 37178825Sdfr/* 38178825Sdfr * Apparently Microsoft got the OID wrong, and used 39178825Sdfr * 1.2.840.48018.1.2.2 instead. We need both this and 40178825Sdfr * the correct Kerberos OID here in order to deal with 41178825Sdfr * this. Because this is manifest in SPNEGO only I'd 42178825Sdfr * prefer to deal with this here rather than inside the 43178825Sdfr * Kerberos mechanism. 44178825Sdfr */ 45178825Sdfrgss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc = 46178825Sdfr {9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"}; 47178825Sdfr 48178825Sdfrgss_OID_desc _gss_spnego_krb5_mechanism_oid_desc = 49178825Sdfr {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 50178825Sdfr 51178825Sdfr/* 52178825Sdfr * Allocate a SPNEGO context handle 53178825Sdfr */ 54178825SdfrOM_uint32 _gss_spnego_alloc_sec_context (OM_uint32 * minor_status, 55178825Sdfr gss_ctx_id_t *context_handle) 56178825Sdfr{ 57178825Sdfr gssspnego_ctx ctx; 58178825Sdfr 59178825Sdfr ctx = calloc(1, sizeof(*ctx)); 60178825Sdfr if (ctx == NULL) { 61178825Sdfr *minor_status = ENOMEM; 62178825Sdfr return GSS_S_FAILURE; 63178825Sdfr } 64178825Sdfr 65178825Sdfr ctx->initiator_mech_types.len = 0; 66178825Sdfr ctx->initiator_mech_types.val = NULL; 67178825Sdfr ctx->preferred_mech_type = GSS_C_NO_OID; 68178825Sdfr ctx->negotiated_mech_type = GSS_C_NO_OID; 69178825Sdfr ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; 70178825Sdfr 71178825Sdfr /* 72178825Sdfr * Cache these so we can return them before returning 73178825Sdfr * GSS_S_COMPLETE, even if the mechanism has itself 74178825Sdfr * completed earlier 75178825Sdfr */ 76178825Sdfr ctx->mech_flags = 0; 77178825Sdfr ctx->mech_time_rec = 0; 78178825Sdfr ctx->mech_src_name = GSS_C_NO_NAME; 79178825Sdfr ctx->delegated_cred_id = GSS_C_NO_CREDENTIAL; 80178825Sdfr 81178825Sdfr ctx->open = 0; 82178825Sdfr ctx->local = 0; 83178825Sdfr ctx->require_mic = 0; 84178825Sdfr ctx->verified_mic = 0; 85178825Sdfr 86178825Sdfr HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); 87178825Sdfr 88178825Sdfr *context_handle = (gss_ctx_id_t)ctx; 89178825Sdfr 90178825Sdfr return GSS_S_COMPLETE; 91178825Sdfr} 92178825Sdfr 93178825Sdfr/* 94178825Sdfr * Free a SPNEGO context handle. The caller must have acquired 95178825Sdfr * the lock before this is called. 96178825Sdfr */ 97178825SdfrOM_uint32 _gss_spnego_internal_delete_sec_context 98178825Sdfr (OM_uint32 *minor_status, 99178825Sdfr gss_ctx_id_t *context_handle, 100178825Sdfr gss_buffer_t output_token 101178825Sdfr ) 102178825Sdfr{ 103178825Sdfr gssspnego_ctx ctx; 104178825Sdfr OM_uint32 ret, minor; 105178825Sdfr 106178825Sdfr *minor_status = 0; 107178825Sdfr 108178825Sdfr if (context_handle == NULL) { 109178825Sdfr return GSS_S_NO_CONTEXT; 110178825Sdfr } 111178825Sdfr 112178825Sdfr if (output_token != GSS_C_NO_BUFFER) { 113178825Sdfr output_token->length = 0; 114178825Sdfr output_token->value = NULL; 115178825Sdfr } 116178825Sdfr 117178825Sdfr ctx = (gssspnego_ctx)*context_handle; 118178825Sdfr *context_handle = GSS_C_NO_CONTEXT; 119178825Sdfr 120178825Sdfr if (ctx == NULL) { 121178825Sdfr return GSS_S_NO_CONTEXT; 122178825Sdfr } 123178825Sdfr 124178825Sdfr if (ctx->initiator_mech_types.val != NULL) 125178825Sdfr free_MechTypeList(&ctx->initiator_mech_types); 126178825Sdfr 127178825Sdfr _gss_spnego_release_cred(&minor, &ctx->delegated_cred_id); 128178825Sdfr 129178825Sdfr gss_release_oid(&minor, &ctx->preferred_mech_type); 130178825Sdfr ctx->negotiated_mech_type = GSS_C_NO_OID; 131178825Sdfr 132178825Sdfr gss_release_name(&minor, &ctx->target_name); 133178825Sdfr gss_release_name(&minor, &ctx->mech_src_name); 134178825Sdfr 135178825Sdfr if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) { 136178825Sdfr ret = gss_delete_sec_context(minor_status, 137178825Sdfr &ctx->negotiated_ctx_id, 138178825Sdfr output_token); 139178825Sdfr ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; 140178825Sdfr } else { 141178825Sdfr ret = GSS_S_COMPLETE; 142178825Sdfr } 143178825Sdfr 144178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 145178825Sdfr HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 146178825Sdfr 147178825Sdfr free(ctx); 148178825Sdfr *context_handle = NULL; 149178825Sdfr 150178825Sdfr return ret; 151178825Sdfr} 152178825Sdfr 153178825Sdfr/* 154178825Sdfr * For compatability with the Windows SPNEGO implementation, the 155178825Sdfr * default is to ignore the mechListMIC unless CFX is used and 156178825Sdfr * a non-preferred mechanism was negotiated 157178825Sdfr */ 158178825Sdfr 159178825SdfrOM_uint32 160178825Sdfr_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, 161178825Sdfr gssspnego_ctx ctx, 162178825Sdfr int *require_mic) 163178825Sdfr{ 164178825Sdfr gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET; 165178825Sdfr OM_uint32 minor; 166178825Sdfr 167178825Sdfr *minor_status = 0; 168178825Sdfr *require_mic = 0; 169178825Sdfr 170178825Sdfr if (ctx == NULL) { 171178825Sdfr return GSS_S_COMPLETE; 172178825Sdfr } 173178825Sdfr 174178825Sdfr if (ctx->require_mic) { 175178825Sdfr /* Acceptor requested it: mandatory to honour */ 176178825Sdfr *require_mic = 1; 177178825Sdfr return GSS_S_COMPLETE; 178178825Sdfr } 179178825Sdfr 180178825Sdfr /* 181178825Sdfr * Check whether peer indicated implicit support for updated SPNEGO 182178825Sdfr * (eg. in the Kerberos case by using CFX) 183178825Sdfr */ 184178825Sdfr if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id, 185178825Sdfr GSS_C_PEER_HAS_UPDATED_SPNEGO, 186178825Sdfr &buffer_set) == GSS_S_COMPLETE) { 187178825Sdfr *require_mic = 1; 188178825Sdfr gss_release_buffer_set(&minor, &buffer_set); 189178825Sdfr } 190178825Sdfr 191178825Sdfr /* Safe-to-omit MIC rules follow */ 192178825Sdfr if (*require_mic) { 193178825Sdfr if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) { 194178825Sdfr *require_mic = 0; 195178825Sdfr } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) && 196178825Sdfr gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) { 197178825Sdfr *require_mic = 0; 198178825Sdfr } 199178825Sdfr } 200178825Sdfr 201178825Sdfr return GSS_S_COMPLETE; 202178825Sdfr} 203178825Sdfr 204178825Sdfrstatic int 205178825Sdfradd_mech_type(gss_OID mech_type, 206178825Sdfr int includeMSCompatOID, 207178825Sdfr MechTypeList *mechtypelist) 208178825Sdfr{ 209178825Sdfr MechType mech; 210178825Sdfr int ret; 211178825Sdfr 212178825Sdfr if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) 213178825Sdfr return 0; 214178825Sdfr 215178825Sdfr if (includeMSCompatOID && 216178825Sdfr gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) { 217178825Sdfr ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements, 218178825Sdfr _gss_spnego_mskrb_mechanism_oid_desc.length, 219178825Sdfr &mech, 220178825Sdfr NULL); 221178825Sdfr if (ret) 222178825Sdfr return ret; 223178825Sdfr ret = add_MechTypeList(mechtypelist, &mech); 224178825Sdfr free_MechType(&mech); 225178825Sdfr if (ret) 226178825Sdfr return ret; 227178825Sdfr } 228178825Sdfr ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL); 229178825Sdfr if (ret) 230178825Sdfr return ret; 231178825Sdfr ret = add_MechTypeList(mechtypelist, &mech); 232178825Sdfr free_MechType(&mech); 233178825Sdfr return ret; 234178825Sdfr} 235178825Sdfr 236178825Sdfr 237178825SdfrOM_uint32 238178825Sdfr_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, 239178825Sdfr gss_name_t target_name, 240178825Sdfr OM_uint32 (*func)(gss_name_t, gss_OID), 241178825Sdfr int includeMSCompatOID, 242178825Sdfr const gssspnego_cred cred_handle, 243178825Sdfr MechTypeList *mechtypelist, 244178825Sdfr gss_OID *preferred_mech) 245178825Sdfr{ 246178825Sdfr gss_OID_set supported_mechs = GSS_C_NO_OID_SET; 247178825Sdfr gss_OID first_mech = GSS_C_NO_OID; 248178825Sdfr OM_uint32 ret; 249178825Sdfr int i; 250178825Sdfr 251178825Sdfr mechtypelist->len = 0; 252178825Sdfr mechtypelist->val = NULL; 253178825Sdfr 254178825Sdfr if (cred_handle != NULL) { 255178825Sdfr ret = gss_inquire_cred(minor_status, 256178825Sdfr cred_handle->negotiated_cred_id, 257178825Sdfr NULL, 258178825Sdfr NULL, 259178825Sdfr NULL, 260178825Sdfr &supported_mechs); 261178825Sdfr } else { 262178825Sdfr ret = gss_indicate_mechs(minor_status, &supported_mechs); 263178825Sdfr } 264178825Sdfr 265178825Sdfr if (ret != GSS_S_COMPLETE) { 266178825Sdfr return ret; 267178825Sdfr } 268178825Sdfr 269178825Sdfr if (supported_mechs->count == 0) { 270178825Sdfr *minor_status = ENOENT; 271178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 272178825Sdfr return GSS_S_FAILURE; 273178825Sdfr } 274178825Sdfr 275178825Sdfr ret = (*func)(target_name, GSS_KRB5_MECHANISM); 276178825Sdfr if (ret == GSS_S_COMPLETE) { 277178825Sdfr ret = add_mech_type(GSS_KRB5_MECHANISM, 278178825Sdfr includeMSCompatOID, 279178825Sdfr mechtypelist); 280178825Sdfr if (!GSS_ERROR(ret)) 281178825Sdfr first_mech = GSS_KRB5_MECHANISM; 282178825Sdfr } 283178825Sdfr ret = GSS_S_COMPLETE; 284178825Sdfr 285178825Sdfr for (i = 0; i < supported_mechs->count; i++) { 286178825Sdfr OM_uint32 subret; 287178825Sdfr if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM)) 288178825Sdfr continue; 289178825Sdfr if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM)) 290178825Sdfr continue; 291178825Sdfr 292178825Sdfr subret = (*func)(target_name, &supported_mechs->elements[i]); 293178825Sdfr if (subret != GSS_S_COMPLETE) 294178825Sdfr continue; 295178825Sdfr 296178825Sdfr ret = add_mech_type(&supported_mechs->elements[i], 297178825Sdfr includeMSCompatOID, 298178825Sdfr mechtypelist); 299178825Sdfr if (ret != 0) { 300178825Sdfr *minor_status = ret; 301178825Sdfr ret = GSS_S_FAILURE; 302178825Sdfr break; 303178825Sdfr } 304178825Sdfr if (first_mech == GSS_C_NO_OID) 305178825Sdfr first_mech = &supported_mechs->elements[i]; 306178825Sdfr } 307178825Sdfr 308178825Sdfr if (mechtypelist->len == 0) { 309178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 310178825Sdfr *minor_status = 0; 311178825Sdfr return GSS_S_BAD_MECH; 312178825Sdfr } 313178825Sdfr 314178825Sdfr if (preferred_mech != NULL) { 315178825Sdfr ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech); 316178825Sdfr if (ret != GSS_S_COMPLETE) 317178825Sdfr free_MechTypeList(mechtypelist); 318178825Sdfr } 319178825Sdfr gss_release_oid_set(minor_status, &supported_mechs); 320178825Sdfr 321178825Sdfr return ret; 322178825Sdfr} 323