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