1/* $NetBSD: gss_mo.c,v 1.2 2017/01/28 21:31:46 christos Exp $ */ 2 3/* 4 * Copyright (c) 2010 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 * Portions Copyright (c) 2010 PADL Software Pty Ltd. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * 3. Neither the name of the Institute nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39#include "mech_locl.h" 40 41#include <crypto-headers.h> 42 43static int 44get_option_def(int def, gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 45{ 46 return def; 47} 48 49int 50_gss_mo_get_option_1(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 51{ 52 return get_option_def(1, mech, mo, value); 53} 54 55int 56_gss_mo_get_option_0(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 57{ 58 return get_option_def(0, mech, mo, value); 59} 60 61int 62_gss_mo_get_ctx_as_string(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 63{ 64 if (value) { 65 value->value = strdup((char *)mo->ctx); 66 if (value->value == NULL) 67 return GSS_S_FAILURE; 68 value->length = strlen((char *)mo->ctx); 69 } 70 return GSS_S_COMPLETE; 71} 72 73GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL 74gss_mo_set(gss_const_OID mech, gss_const_OID option, 75 int enable, gss_buffer_t value) 76{ 77 gssapi_mech_interface m; 78 size_t n; 79 80 if ((m = __gss_get_mechanism(mech)) == NULL) 81 return GSS_S_BAD_MECH; 82 83 for (n = 0; n < m->gm_mo_num; n++) 84 if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].set) 85 return m->gm_mo[n].set(mech, &m->gm_mo[n], enable, value); 86 87 return GSS_S_UNAVAILABLE; 88} 89 90GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL 91gss_mo_get(gss_const_OID mech, gss_const_OID option, gss_buffer_t value) 92{ 93 gssapi_mech_interface m; 94 size_t n; 95 96 _mg_buffer_zero(value); 97 98 if ((m = __gss_get_mechanism(mech)) == NULL) 99 return GSS_S_BAD_MECH; 100 101 for (n = 0; n < m->gm_mo_num; n++) 102 if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].get) 103 return m->gm_mo[n].get(mech, &m->gm_mo[n], value); 104 105 return GSS_S_UNAVAILABLE; 106} 107 108static void 109add_all_mo(gssapi_mech_interface m, gss_OID_set *options, OM_uint32 mask) 110{ 111 OM_uint32 minor; 112 size_t n; 113 114 for (n = 0; n < m->gm_mo_num; n++) 115 if ((m->gm_mo[n].flags & mask) == mask) 116 gss_add_oid_set_member(&minor, m->gm_mo[n].option, options); 117} 118 119GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL 120gss_mo_list(gss_const_OID mech, gss_OID_set *options) 121{ 122 gssapi_mech_interface m; 123 OM_uint32 major, minor; 124 125 if (options == NULL) 126 return; 127 128 *options = GSS_C_NO_OID_SET; 129 130 if ((m = __gss_get_mechanism(mech)) == NULL) 131 return; 132 133 major = gss_create_empty_oid_set(&minor, options); 134 if (major != GSS_S_COMPLETE) 135 return; 136 137 add_all_mo(m, options, 0); 138} 139 140GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 141gss_mo_name(gss_const_OID mech, gss_const_OID option, gss_buffer_t name) 142{ 143 gssapi_mech_interface m; 144 size_t n; 145 146 if (name == NULL) 147 return GSS_S_BAD_NAME; 148 149 if ((m = __gss_get_mechanism(mech)) == NULL) 150 return GSS_S_BAD_MECH; 151 152 for (n = 0; n < m->gm_mo_num; n++) { 153 if (gss_oid_equal(option, m->gm_mo[n].option)) { 154 /* 155 * If there is no name, its because its a GSS_C_MA and 156 * there is already a table for that. 157 */ 158 if (m->gm_mo[n].name) { 159 name->value = strdup(m->gm_mo[n].name); 160 if (name->value == NULL) 161 return GSS_S_BAD_NAME; 162 name->length = strlen(m->gm_mo[n].name); 163 return GSS_S_COMPLETE; 164 } else { 165 OM_uint32 junk; 166 return gss_display_mech_attr(&junk, option, 167 NULL, name, NULL); 168 } 169 } 170 } 171 return GSS_S_BAD_NAME; 172} 173 174/* 175 * Helper function to allow NULL name 176 */ 177 178static OM_uint32 179mo_value(const gss_const_OID mech, gss_const_OID option, gss_buffer_t name) 180{ 181 if (name == NULL) 182 return GSS_S_COMPLETE; 183 184 return gss_mo_get(mech, option, name); 185} 186 187/* code derived from draft-ietf-cat-sasl-gssapi-01 */ 188static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 189 190static OM_uint32 191make_sasl_name(OM_uint32 *minor, const gss_OID mech, char sasl_name[16]) 192{ 193 EVP_MD_CTX *ctx; 194 char *p = sasl_name; 195 u_char hdr[2], hash[20], *h = hash; 196 197 if (mech->length > 127) 198 return GSS_S_BAD_MECH; 199 200 hdr[0] = 0x06; 201 hdr[1] = mech->length; 202 203 ctx = EVP_MD_CTX_create(); 204 EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); 205 EVP_DigestUpdate(ctx, hdr, 2); 206 EVP_DigestUpdate(ctx, mech->elements, mech->length); 207 EVP_DigestFinal_ex(ctx, hash, NULL); 208 EVP_MD_CTX_destroy(ctx); 209 210 memcpy(p, "GS2-", 4); 211 p += 4; 212 213 *p++ = basis_32[(h[0] >> 3)]; 214 *p++ = basis_32[((h[0] & 7) << 2) | (h[1] >> 6)]; 215 *p++ = basis_32[(h[1] & 0x3f) >> 1]; 216 *p++ = basis_32[((h[1] & 1) << 4) | (h[2] >> 4)]; 217 *p++ = basis_32[((h[2] & 0xf) << 1) | (h[3] >> 7)]; 218 *p++ = basis_32[(h[3] & 0x7f) >> 2]; 219 *p++ = basis_32[((h[3] & 3) << 3) | (h[4] >> 5)]; 220 *p++ = basis_32[(h[4] & 0x1f)]; 221 *p++ = basis_32[(h[5] >> 3)]; 222 *p++ = basis_32[((h[5] & 7) << 2) | (h[6] >> 6)]; 223 *p++ = basis_32[(h[6] & 0x3f) >> 1]; 224 225 *p = '\0'; 226 227 return GSS_S_COMPLETE; 228} 229 230/* 231 * gss_inquire_saslname_for_mech() wrapper that uses MIT SPI 232 */ 233static OM_uint32 234inquire_saslname_for_mech_compat(OM_uint32 *minor, 235 const gss_OID desired_mech, 236 gss_buffer_t sasl_mech_name, 237 gss_buffer_t mech_name, 238 gss_buffer_t mech_description) 239{ 240 struct gss_mech_compat_desc_struct *gmc; 241 gssapi_mech_interface m; 242 OM_uint32 major; 243 244 m = __gss_get_mechanism(desired_mech); 245 if (m == NULL) 246 return GSS_S_BAD_MECH; 247 248 gmc = m->gm_compat; 249 250 if (gmc != NULL && gmc->gmc_inquire_saslname_for_mech != NULL) { 251 major = gmc->gmc_inquire_saslname_for_mech(minor, 252 desired_mech, 253 sasl_mech_name, 254 mech_name, 255 mech_description); 256 } else { 257 major = GSS_S_UNAVAILABLE; 258 } 259 260 return major; 261} 262 263/** 264 * Returns different protocol names and description of the mechanism. 265 * 266 * @param minor_status minor status code 267 * @param desired_mech mech list query 268 * @param sasl_mech_name SASL GS2 protocol name 269 * @param mech_name gssapi protocol name 270 * @param mech_description description of gssapi mech 271 * 272 * @return returns GSS_S_COMPLETE or a error code. 273 * 274 * @ingroup gssapi 275 */ 276 277GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 278gss_inquire_saslname_for_mech(OM_uint32 *minor_status, 279 const gss_OID desired_mech, 280 gss_buffer_t sasl_mech_name, 281 gss_buffer_t mech_name, 282 gss_buffer_t mech_description) 283{ 284 OM_uint32 major; 285 286 _mg_buffer_zero(sasl_mech_name); 287 _mg_buffer_zero(mech_name); 288 _mg_buffer_zero(mech_description); 289 290 if (minor_status) 291 *minor_status = 0; 292 293 if (desired_mech == NULL) 294 return GSS_S_BAD_MECH; 295 296 major = mo_value(desired_mech, GSS_C_MA_SASL_MECH_NAME, sasl_mech_name); 297 if (major == GSS_S_COMPLETE) { 298 /* Native SPI */ 299 major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name); 300 if (GSS_ERROR(major)) 301 return major; 302 303 major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description); 304 if (GSS_ERROR(major)) 305 return major; 306 } 307 308 if (GSS_ERROR(major)) { 309 /* API-as-SPI compatibility */ 310 major = inquire_saslname_for_mech_compat(minor_status, 311 desired_mech, 312 sasl_mech_name, 313 mech_name, 314 mech_description); 315 } 316 317 if (GSS_ERROR(major)) { 318 /* Algorithmically dervied SASL mechanism name */ 319 char buf[16]; 320 gss_buffer_desc tmp = { sizeof(buf) - 1, buf }; 321 322 major = make_sasl_name(minor_status, desired_mech, buf); 323 if (GSS_ERROR(major)) 324 return major; 325 326 major = _gss_copy_buffer(minor_status, &tmp, sasl_mech_name); 327 if (GSS_ERROR(major)) 328 return major; 329 } 330 331 return major; 332} 333 334/** 335 * Find a mech for a sasl name 336 * 337 * @param minor_status minor status code 338 * @param sasl_mech_name 339 * @param mech_type 340 * 341 * @return returns GSS_S_COMPLETE or an error code. 342 */ 343 344GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 345gss_inquire_mech_for_saslname(OM_uint32 *minor_status, 346 const gss_buffer_t sasl_mech_name, 347 gss_OID *mech_type) 348{ 349 struct _gss_mech_switch *m; 350 gss_buffer_desc name; 351 OM_uint32 major, junk; 352 char buf[16]; 353 354 _gss_load_mech(); 355 356 *mech_type = NULL; 357 358 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 359 struct gss_mech_compat_desc_struct *gmc; 360 361 /* Native SPI */ 362 major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); 363 if (major == GSS_S_COMPLETE && 364 name.length == sasl_mech_name->length && 365 memcmp(name.value, sasl_mech_name->value, name.length) == 0) { 366 gss_release_buffer(&junk, &name); 367 *mech_type = &m->gm_mech_oid; 368 return GSS_S_COMPLETE; 369 } 370 gss_release_buffer(&junk, &name); 371 372 if (GSS_ERROR(major)) { 373 /* API-as-SPI compatibility */ 374 gmc = m->gm_mech.gm_compat; 375 if (gmc && gmc->gmc_inquire_mech_for_saslname) { 376 major = gmc->gmc_inquire_mech_for_saslname(minor_status, 377 sasl_mech_name, 378 mech_type); 379 if (major == GSS_S_COMPLETE) 380 return GSS_S_COMPLETE; 381 } 382 } 383 384 if (GSS_ERROR(major)) { 385 /* Algorithmically dervied SASL mechanism name */ 386 if (sasl_mech_name->length == 16 && 387 make_sasl_name(minor_status, &m->gm_mech_oid, buf) == GSS_S_COMPLETE && 388 memcmp(buf, sasl_mech_name->value, 16) == 0) { 389 *mech_type = &m->gm_mech_oid; 390 return GSS_S_COMPLETE; 391 } 392 } 393 } 394 395 return GSS_S_BAD_MECH; 396} 397 398/* 399 * Test mechanism against indicated attributes using both Heimdal and 400 * MIT SPIs. 401 */ 402static int 403test_mech_attrs(gssapi_mech_interface mi, 404 gss_const_OID_set mech_attrs, 405 gss_const_OID_set against_attrs, 406 int except) 407{ 408 size_t n, m; 409 int eq = 0; 410 411 if (against_attrs == GSS_C_NO_OID_SET) 412 return 1; 413 414 for (n = 0; n < against_attrs->count; n++) { 415 for (m = 0; m < mi->gm_mo_num; m++) { 416 eq = gss_oid_equal(mi->gm_mo[m].option, 417 &against_attrs->elements[n]); 418 if (eq) 419 break; 420 } 421 if (mech_attrs != GSS_C_NO_OID_SET) { 422 for (m = 0; m < mech_attrs->count; m++) { 423 eq = gss_oid_equal(&mech_attrs->elements[m], 424 &against_attrs->elements[n]); 425 if (eq) 426 break; 427 } 428 } 429 if (!eq ^ except) 430 return 0; 431 } 432 433 return 1; 434} 435 436/** 437 * Return set of mechanism that fullfill the criteria 438 * 439 * @param minor_status minor status code 440 * @param desired_mech_attrs 441 * @param except_mech_attrs 442 * @param critical_mech_attrs 443 * @param mechs returned mechs, free with gss_release_oid_set(). 444 * 445 * @return returns GSS_S_COMPLETE or an error code. 446 */ 447 448GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 449gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, 450 gss_const_OID_set desired_mech_attrs, 451 gss_const_OID_set except_mech_attrs, 452 gss_const_OID_set critical_mech_attrs, 453 gss_OID_set *mechs) 454{ 455 struct _gss_mech_switch *ms; 456 gss_OID_set mech_attrs = GSS_C_NO_OID_SET; 457 gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET; 458 OM_uint32 major; 459 460 major = gss_create_empty_oid_set(minor_status, mechs); 461 if (GSS_ERROR(major)) 462 return major; 463 464 _gss_load_mech(); 465 466 HEIM_SLIST_FOREACH(ms, &_gss_mechs, gm_link) { 467 gssapi_mech_interface mi = &ms->gm_mech; 468 struct gss_mech_compat_desc_struct *gmc = mi->gm_compat; 469 OM_uint32 tmp; 470 471 if (gmc && gmc->gmc_inquire_attrs_for_mech) { 472 major = gmc->gmc_inquire_attrs_for_mech(minor_status, 473 &mi->gm_mech_oid, 474 &mech_attrs, 475 &known_mech_attrs); 476 if (GSS_ERROR(major)) 477 continue; 478 } 479 480 /* 481 * Test mechanism supports all of desired_mech_attrs; 482 * none of except_mech_attrs; 483 * and knows of all critical_mech_attrs. 484 */ 485 if (test_mech_attrs(mi, mech_attrs, desired_mech_attrs, 0) && 486 test_mech_attrs(mi, mech_attrs, except_mech_attrs, 1) && 487 test_mech_attrs(mi, known_mech_attrs, critical_mech_attrs, 0)) { 488 major = gss_add_oid_set_member(minor_status, &mi->gm_mech_oid, mechs); 489 } 490 491 gss_release_oid_set(&tmp, &mech_attrs); 492 gss_release_oid_set(&tmp, &known_mech_attrs); 493 494 if (GSS_ERROR(major)) 495 break; 496 } 497 498 return major; 499} 500 501/** 502 * List support attributes for a mech and/or all mechanisms. 503 * 504 * @param minor_status minor status code 505 * @param mech given together with mech_attr will return the list of 506 * attributes for mechanism, can optionally be GSS_C_NO_OID. 507 * @param mech_attr see mech parameter, can optionally be NULL, 508 * release with gss_release_oid_set(). 509 * @param known_mech_attrs all attributes for mechanisms supported, 510 * release with gss_release_oid_set(). 511 * 512 * @ingroup gssapi 513 */ 514 515GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 516gss_inquire_attrs_for_mech(OM_uint32 * minor_status, 517 gss_const_OID mech, 518 gss_OID_set *mech_attr, 519 gss_OID_set *known_mech_attrs) 520{ 521 OM_uint32 major, junk; 522 523 if (known_mech_attrs) 524 *known_mech_attrs = GSS_C_NO_OID_SET; 525 526 if (mech_attr && mech) { 527 gssapi_mech_interface m; 528 struct gss_mech_compat_desc_struct *gmc; 529 530 if ((m = __gss_get_mechanism(mech)) == NULL) { 531 *minor_status = 0; 532 return GSS_S_BAD_MECH; 533 } 534 535 gmc = m->gm_compat; 536 537 if (gmc && gmc->gmc_inquire_attrs_for_mech) { 538 major = gmc->gmc_inquire_attrs_for_mech(minor_status, 539 mech, 540 mech_attr, 541 known_mech_attrs); 542 } else { 543 major = gss_create_empty_oid_set(minor_status, mech_attr); 544 if (major == GSS_S_COMPLETE) 545 add_all_mo(m, mech_attr, GSS_MO_MA); 546 } 547 if (GSS_ERROR(major)) 548 return major; 549 } 550 551 if (known_mech_attrs) { 552 struct _gss_mech_switch *m; 553 554 if (*known_mech_attrs == GSS_C_NO_OID_SET) { 555 major = gss_create_empty_oid_set(minor_status, known_mech_attrs); 556 if (GSS_ERROR(major)) { 557 if (mech_attr) 558 gss_release_oid_set(&junk, mech_attr); 559 return major; 560 } 561 } 562 563 _gss_load_mech(); 564 565 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) 566 add_all_mo(&m->gm_mech, known_mech_attrs, GSS_MO_MA); 567 } 568 569 570 return GSS_S_COMPLETE; 571} 572 573/** 574 * Return names and descriptions of mech attributes 575 * 576 * @param minor_status minor status code 577 * @param mech_attr 578 * @param name 579 * @param short_desc 580 * @param long_desc 581 * 582 * @return returns GSS_S_COMPLETE or an error code. 583 */ 584 585GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 586gss_display_mech_attr(OM_uint32 * minor_status, 587 gss_const_OID mech_attr, 588 gss_buffer_t name, 589 gss_buffer_t short_desc, 590 gss_buffer_t long_desc) 591{ 592 struct _gss_oid_name_table *ma = NULL; 593 OM_uint32 major; 594 size_t n; 595 596 _mg_buffer_zero(name); 597 _mg_buffer_zero(short_desc); 598 _mg_buffer_zero(long_desc); 599 600 if (minor_status) 601 *minor_status = 0; 602 603 for (n = 0; ma == NULL && _gss_ont_ma[n].oid; n++) 604 if (gss_oid_equal(mech_attr, _gss_ont_ma[n].oid)) 605 ma = &_gss_ont_ma[n]; 606 607 if (ma == NULL) 608 return GSS_S_BAD_MECH_ATTR; 609 610 if (name) { 611 gss_buffer_desc bd; 612 bd.value = rk_UNCONST(ma->name); 613 bd.length = strlen(ma->name); 614 major = _gss_copy_buffer(minor_status, &bd, name); 615 if (major != GSS_S_COMPLETE) 616 return major; 617 } 618 619 if (short_desc) { 620 gss_buffer_desc bd; 621 bd.value = rk_UNCONST(ma->short_desc); 622 bd.length = strlen(ma->short_desc); 623 major = _gss_copy_buffer(minor_status, &bd, short_desc); 624 if (major != GSS_S_COMPLETE) 625 return major; 626 } 627 628 if (long_desc) { 629 gss_buffer_desc bd; 630 bd.value = rk_UNCONST(ma->long_desc); 631 bd.length = strlen(ma->long_desc); 632 major = _gss_copy_buffer(minor_status, &bd, long_desc); 633 if (major != GSS_S_COMPLETE) 634 return major; 635 } 636 637 return GSS_S_COMPLETE; 638} 639