Path: blob/main/crypto/heimdal/lib/gssapi/mech/gss_mo.c
34907 views
/*1* Copyright (c) 2010 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Portions Copyright (c) 2010 Apple Inc. All rights reserved.6* Portions Copyright (c) 2010 PADL Software Pty Ltd. All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11*12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14*15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* 3. Neither the name of the Institute nor the names of its contributors20* may be used to endorse or promote products derived from this software21* without specific prior written permission.22*23* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND24* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE25* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE26* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE27* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL28* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS29* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)30* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT31* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY32* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF33* SUCH DAMAGE.34*/3536#include "mech_locl.h"3738#include <crypto-headers.h>3940static int41get_option_def(int def, gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value)42{43return def;44}4546int47_gss_mo_get_option_1(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value)48{49return get_option_def(1, mech, mo, value);50}5152int53_gss_mo_get_option_0(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value)54{55return get_option_def(0, mech, mo, value);56}5758int59_gss_mo_get_ctx_as_string(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value)60{61if (value) {62value->value = strdup((char *)mo->ctx);63if (value->value == NULL)64return GSS_S_FAILURE;65value->length = strlen((char *)mo->ctx);66}67return GSS_S_COMPLETE;68}6970GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL71gss_mo_set(gss_const_OID mech, gss_const_OID option,72int enable, gss_buffer_t value)73{74gssapi_mech_interface m;75size_t n;7677if ((m = __gss_get_mechanism(mech)) == NULL)78return GSS_S_BAD_MECH;7980for (n = 0; n < m->gm_mo_num; n++)81if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].set)82return m->gm_mo[n].set(mech, &m->gm_mo[n], enable, value);8384return GSS_S_UNAVAILABLE;85}8687GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL88gss_mo_get(gss_const_OID mech, gss_const_OID option, gss_buffer_t value)89{90gssapi_mech_interface m;91size_t n;9293_mg_buffer_zero(value);9495if ((m = __gss_get_mechanism(mech)) == NULL)96return GSS_S_BAD_MECH;9798for (n = 0; n < m->gm_mo_num; n++)99if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].get)100return m->gm_mo[n].get(mech, &m->gm_mo[n], value);101102return GSS_S_UNAVAILABLE;103}104105static void106add_all_mo(gssapi_mech_interface m, gss_OID_set *options, OM_uint32 mask)107{108OM_uint32 minor;109size_t n;110111for (n = 0; n < m->gm_mo_num; n++)112if ((m->gm_mo[n].flags & mask) == mask)113gss_add_oid_set_member(&minor, m->gm_mo[n].option, options);114}115116GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL117gss_mo_list(gss_const_OID mech, gss_OID_set *options)118{119gssapi_mech_interface m;120OM_uint32 major, minor;121122if (options == NULL)123return;124125*options = GSS_C_NO_OID_SET;126127if ((m = __gss_get_mechanism(mech)) == NULL)128return;129130major = gss_create_empty_oid_set(&minor, options);131if (major != GSS_S_COMPLETE)132return;133134add_all_mo(m, options, 0);135}136137GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL138gss_mo_name(gss_const_OID mech, gss_const_OID option, gss_buffer_t name)139{140gssapi_mech_interface m;141size_t n;142143if (name == NULL)144return GSS_S_BAD_NAME;145146if ((m = __gss_get_mechanism(mech)) == NULL)147return GSS_S_BAD_MECH;148149for (n = 0; n < m->gm_mo_num; n++) {150if (gss_oid_equal(option, m->gm_mo[n].option)) {151/*152* If there is no name, its because its a GSS_C_MA and153* there is already a table for that.154*/155if (m->gm_mo[n].name) {156name->value = strdup(m->gm_mo[n].name);157if (name->value == NULL)158return GSS_S_BAD_NAME;159name->length = strlen(m->gm_mo[n].name);160return GSS_S_COMPLETE;161} else {162OM_uint32 junk;163return gss_display_mech_attr(&junk, option,164NULL, name, NULL);165}166}167}168return GSS_S_BAD_NAME;169}170171/*172* Helper function to allow NULL name173*/174175static OM_uint32176mo_value(const gss_const_OID mech, gss_const_OID option, gss_buffer_t name)177{178if (name == NULL)179return GSS_S_COMPLETE;180181return gss_mo_get(mech, option, name);182}183184/* code derived from draft-ietf-cat-sasl-gssapi-01 */185static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";186187static OM_uint32188make_sasl_name(OM_uint32 *minor, const gss_OID mech, char sasl_name[16])189{190EVP_MD_CTX *ctx;191char *p = sasl_name;192u_char hdr[2], hash[20], *h = hash;193194if (mech->length > 127)195return GSS_S_BAD_MECH;196197hdr[0] = 0x06;198hdr[1] = mech->length;199200ctx = EVP_MD_CTX_create();201EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);202EVP_DigestUpdate(ctx, hdr, 2);203EVP_DigestUpdate(ctx, mech->elements, mech->length);204EVP_DigestFinal_ex(ctx, hash, NULL);205206memcpy(p, "GS2-", 4);207p += 4;208209*p++ = basis_32[(h[0] >> 3)];210*p++ = basis_32[((h[0] & 7) << 2) | (h[1] >> 6)];211*p++ = basis_32[(h[1] & 0x3f) >> 1];212*p++ = basis_32[((h[1] & 1) << 4) | (h[2] >> 4)];213*p++ = basis_32[((h[2] & 0xf) << 1) | (h[3] >> 7)];214*p++ = basis_32[(h[3] & 0x7f) >> 2];215*p++ = basis_32[((h[3] & 3) << 3) | (h[4] >> 5)];216*p++ = basis_32[(h[4] & 0x1f)];217*p++ = basis_32[(h[5] >> 3)];218*p++ = basis_32[((h[5] & 7) << 2) | (h[6] >> 6)];219*p++ = basis_32[(h[6] & 0x3f) >> 1];220221*p = '\0';222223return GSS_S_COMPLETE;224}225226/*227* gss_inquire_saslname_for_mech() wrapper that uses MIT SPI228*/229static OM_uint32230inquire_saslname_for_mech_compat(OM_uint32 *minor,231const gss_OID desired_mech,232gss_buffer_t sasl_mech_name,233gss_buffer_t mech_name,234gss_buffer_t mech_description)235{236struct gss_mech_compat_desc_struct *gmc;237gssapi_mech_interface m;238OM_uint32 major;239240m = __gss_get_mechanism(desired_mech);241if (m == NULL)242return GSS_S_BAD_MECH;243244gmc = m->gm_compat;245246if (gmc != NULL && gmc->gmc_inquire_saslname_for_mech != NULL) {247major = gmc->gmc_inquire_saslname_for_mech(minor,248desired_mech,249sasl_mech_name,250mech_name,251mech_description);252} else {253major = GSS_S_UNAVAILABLE;254}255256return major;257}258259/**260* Returns different protocol names and description of the mechanism.261*262* @param minor_status minor status code263* @param desired_mech mech list query264* @param sasl_mech_name SASL GS2 protocol name265* @param mech_name gssapi protocol name266* @param mech_description description of gssapi mech267*268* @return returns GSS_S_COMPLETE or a error code.269*270* @ingroup gssapi271*/272273GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL274gss_inquire_saslname_for_mech(OM_uint32 *minor_status,275const gss_OID desired_mech,276gss_buffer_t sasl_mech_name,277gss_buffer_t mech_name,278gss_buffer_t mech_description)279{280OM_uint32 major;281282_mg_buffer_zero(sasl_mech_name);283_mg_buffer_zero(mech_name);284_mg_buffer_zero(mech_description);285286if (minor_status)287*minor_status = 0;288289if (desired_mech == NULL)290return GSS_S_BAD_MECH;291292major = mo_value(desired_mech, GSS_C_MA_SASL_MECH_NAME, sasl_mech_name);293if (major == GSS_S_COMPLETE) {294/* Native SPI */295major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name);296if (GSS_ERROR(major))297return major;298299major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description);300if (GSS_ERROR(major))301return major;302}303304if (GSS_ERROR(major)) {305/* API-as-SPI compatibility */306major = inquire_saslname_for_mech_compat(minor_status,307desired_mech,308sasl_mech_name,309mech_name,310mech_description);311}312313if (GSS_ERROR(major)) {314/* Algorithmically dervied SASL mechanism name */315char buf[16];316gss_buffer_desc tmp = { sizeof(buf) - 1, buf };317318major = make_sasl_name(minor_status, desired_mech, buf);319if (GSS_ERROR(major))320return major;321322major = _gss_copy_buffer(minor_status, &tmp, sasl_mech_name);323if (GSS_ERROR(major))324return major;325}326327return major;328}329330/**331* Find a mech for a sasl name332*333* @param minor_status minor status code334* @param sasl_mech_name335* @param mech_type336*337* @return returns GSS_S_COMPLETE or an error code.338*/339340GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL341gss_inquire_mech_for_saslname(OM_uint32 *minor_status,342const gss_buffer_t sasl_mech_name,343gss_OID *mech_type)344{345struct _gss_mech_switch *m;346gss_buffer_desc name;347OM_uint32 major, junk;348char buf[16];349350_gss_load_mech();351352*mech_type = NULL;353354HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {355struct gss_mech_compat_desc_struct *gmc;356357/* Native SPI */358major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name);359if (major == GSS_S_COMPLETE &&360name.length == sasl_mech_name->length &&361memcmp(name.value, sasl_mech_name->value, name.length) == 0) {362gss_release_buffer(&junk, &name);363*mech_type = &m->gm_mech_oid;364return GSS_S_COMPLETE;365}366gss_release_buffer(&junk, &name);367368if (GSS_ERROR(major)) {369/* API-as-SPI compatibility */370gmc = m->gm_mech.gm_compat;371if (gmc && gmc->gmc_inquire_mech_for_saslname) {372major = gmc->gmc_inquire_mech_for_saslname(minor_status,373sasl_mech_name,374mech_type);375if (major == GSS_S_COMPLETE)376return GSS_S_COMPLETE;377}378}379380if (GSS_ERROR(major)) {381/* Algorithmically dervied SASL mechanism name */382if (sasl_mech_name->length == 16 &&383make_sasl_name(minor_status, &m->gm_mech_oid, buf) == GSS_S_COMPLETE &&384memcmp(buf, sasl_mech_name->value, 16) == 0) {385*mech_type = &m->gm_mech_oid;386return GSS_S_COMPLETE;387}388}389}390391return GSS_S_BAD_MECH;392}393394/*395* Test mechanism against indicated attributes using both Heimdal and396* MIT SPIs.397*/398static int399test_mech_attrs(gssapi_mech_interface mi,400gss_const_OID_set mech_attrs,401gss_const_OID_set against_attrs,402int except)403{404size_t n, m;405int eq = 0;406407if (against_attrs == GSS_C_NO_OID_SET)408return 1;409410for (n = 0; n < against_attrs->count; n++) {411for (m = 0; m < mi->gm_mo_num; m++) {412eq = gss_oid_equal(mi->gm_mo[m].option,413&against_attrs->elements[n]);414if (eq)415break;416}417if (mech_attrs != GSS_C_NO_OID_SET) {418for (m = 0; m < mech_attrs->count; m++) {419eq = gss_oid_equal(&mech_attrs->elements[m],420&against_attrs->elements[n]);421if (eq)422break;423}424}425if (!eq ^ except)426return 0;427}428429return 1;430}431432/**433* Return set of mechanism that fullfill the criteria434*435* @param minor_status minor status code436* @param desired_mech_attrs437* @param except_mech_attrs438* @param critical_mech_attrs439* @param mechs returned mechs, free with gss_release_oid_set().440*441* @return returns GSS_S_COMPLETE or an error code.442*/443444GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL445gss_indicate_mechs_by_attrs(OM_uint32 * minor_status,446gss_const_OID_set desired_mech_attrs,447gss_const_OID_set except_mech_attrs,448gss_const_OID_set critical_mech_attrs,449gss_OID_set *mechs)450{451struct _gss_mech_switch *ms;452gss_OID_set mech_attrs = GSS_C_NO_OID_SET;453gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET;454OM_uint32 major;455456major = gss_create_empty_oid_set(minor_status, mechs);457if (GSS_ERROR(major))458return major;459460_gss_load_mech();461462HEIM_SLIST_FOREACH(ms, &_gss_mechs, gm_link) {463gssapi_mech_interface mi = &ms->gm_mech;464struct gss_mech_compat_desc_struct *gmc = mi->gm_compat;465OM_uint32 tmp;466467if (gmc && gmc->gmc_inquire_attrs_for_mech) {468major = gmc->gmc_inquire_attrs_for_mech(minor_status,469&mi->gm_mech_oid,470&mech_attrs,471&known_mech_attrs);472if (GSS_ERROR(major))473continue;474}475476/*477* Test mechanism supports all of desired_mech_attrs;478* none of except_mech_attrs;479* and knows of all critical_mech_attrs.480*/481if (test_mech_attrs(mi, mech_attrs, desired_mech_attrs, 0) &&482test_mech_attrs(mi, mech_attrs, except_mech_attrs, 1) &&483test_mech_attrs(mi, known_mech_attrs, critical_mech_attrs, 0)) {484major = gss_add_oid_set_member(minor_status, &mi->gm_mech_oid, mechs);485}486487gss_release_oid_set(&tmp, &mech_attrs);488gss_release_oid_set(&tmp, &known_mech_attrs);489490if (GSS_ERROR(major))491break;492}493494return major;495}496497/**498* List support attributes for a mech and/or all mechanisms.499*500* @param minor_status minor status code501* @param mech given together with mech_attr will return the list of502* attributes for mechanism, can optionally be GSS_C_NO_OID.503* @param mech_attr see mech parameter, can optionally be NULL,504* release with gss_release_oid_set().505* @param known_mech_attrs all attributes for mechanisms supported,506* release with gss_release_oid_set().507*508* @ingroup gssapi509*/510511GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL512gss_inquire_attrs_for_mech(OM_uint32 * minor_status,513gss_const_OID mech,514gss_OID_set *mech_attr,515gss_OID_set *known_mech_attrs)516{517OM_uint32 major, junk;518519if (known_mech_attrs)520*known_mech_attrs = GSS_C_NO_OID_SET;521522if (mech_attr && mech) {523gssapi_mech_interface m;524struct gss_mech_compat_desc_struct *gmc;525526if ((m = __gss_get_mechanism(mech)) == NULL) {527*minor_status = 0;528return GSS_S_BAD_MECH;529}530531gmc = m->gm_compat;532533if (gmc && gmc->gmc_inquire_attrs_for_mech) {534major = gmc->gmc_inquire_attrs_for_mech(minor_status,535mech,536mech_attr,537known_mech_attrs);538} else {539major = gss_create_empty_oid_set(minor_status, mech_attr);540if (major == GSS_S_COMPLETE)541add_all_mo(m, mech_attr, GSS_MO_MA);542}543if (GSS_ERROR(major))544return major;545}546547if (known_mech_attrs) {548struct _gss_mech_switch *m;549550if (*known_mech_attrs == GSS_C_NO_OID_SET) {551major = gss_create_empty_oid_set(minor_status, known_mech_attrs);552if (GSS_ERROR(major)) {553if (mech_attr)554gss_release_oid_set(&junk, mech_attr);555return major;556}557}558559_gss_load_mech();560561HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link)562add_all_mo(&m->gm_mech, known_mech_attrs, GSS_MO_MA);563}564565566return GSS_S_COMPLETE;567}568569/**570* Return names and descriptions of mech attributes571*572* @param minor_status minor status code573* @param mech_attr574* @param name575* @param short_desc576* @param long_desc577*578* @return returns GSS_S_COMPLETE or an error code.579*/580581GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL582gss_display_mech_attr(OM_uint32 * minor_status,583gss_const_OID mech_attr,584gss_buffer_t name,585gss_buffer_t short_desc,586gss_buffer_t long_desc)587{588struct _gss_oid_name_table *ma = NULL;589OM_uint32 major;590size_t n;591592_mg_buffer_zero(name);593_mg_buffer_zero(short_desc);594_mg_buffer_zero(long_desc);595596if (minor_status)597*minor_status = 0;598599for (n = 0; ma == NULL && _gss_ont_ma[n].oid; n++)600if (gss_oid_equal(mech_attr, _gss_ont_ma[n].oid))601ma = &_gss_ont_ma[n];602603if (ma == NULL)604return GSS_S_BAD_MECH_ATTR;605606if (name) {607gss_buffer_desc bd;608bd.value = rk_UNCONST(ma->name);609bd.length = strlen(ma->name);610major = _gss_copy_buffer(minor_status, &bd, name);611if (major != GSS_S_COMPLETE)612return major;613}614615if (short_desc) {616gss_buffer_desc bd;617bd.value = rk_UNCONST(ma->short_desc);618bd.length = strlen(ma->short_desc);619major = _gss_copy_buffer(minor_status, &bd, short_desc);620if (major != GSS_S_COMPLETE)621return major;622}623624if (long_desc) {625gss_buffer_desc bd;626bd.value = rk_UNCONST(ma->long_desc);627bd.length = strlen(ma->long_desc);628major = _gss_copy_buffer(minor_status, &bd, long_desc);629if (major != GSS_S_COMPLETE)630return major;631}632633return GSS_S_COMPLETE;634}635636637