1 /* $NetBSD: spnego.c,v 1.8 2014/12/10 04:37:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2006-2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Id */ 20 21 /*! \file 22 * \brief 23 * Portable SPNEGO implementation. 24 * 25 * This is part of a portable implementation of the SPNEGO protocol 26 * (RFCs 2478 and 4178). This implementation uses the RFC 4178 ASN.1 27 * module but is not a full implementation of the RFC 4178 protocol; 28 * at the moment, we only support GSS-TSIG with Kerberos 29 * authentication, so we only need enough of the SPNEGO protocol to 30 * support that. 31 * 32 * The files that make up this portable SPNEGO implementation are: 33 * \li spnego.c (this file) 34 * \li spnego.h (API SPNEGO exports to the rest of lib/dns) 35 * \li spnego.asn1 (SPNEGO ASN.1 module) 36 * \li spnego_asn1.c (routines generated from spngo.asn1) 37 * \li spnego_asn1.pl (perl script to generate spnego_asn1.c) 38 * 39 * Everything but the functions exported in spnego.h is static, to 40 * avoid possible conflicts with other libraries (particularly Heimdal, 41 * since much of this code comes from Heimdal by way of mod_auth_kerb). 42 * 43 * spnego_asn1.c is shipped as part of lib/dns because generating it 44 * requires both Perl and the Heimdal ASN.1 compiler. See 45 * spnego_asn1.pl for further details. We've tried to eliminate all 46 * compiler warnings from the generated code, but you may see a few 47 * when using a compiler version we haven't tested yet. 48 */ 49 50 /* 51 * Portions of this code were derived from mod_auth_kerb and Heimdal. 52 * These packages are available from: 53 * 54 * http://modauthkerb.sourceforge.net/ 55 * http://www.pdc.kth.se/heimdal/ 56 * 57 * and were released under the following licenses: 58 * 59 * ---------------------------------------------------------------- 60 * 61 * Copyright (c) 2004 Masarykova universita 62 * (Masaryk University, Brno, Czech Republic) 63 * All rights reserved. 64 * 65 * Redistribution and use in source and binary forms, with or without 66 * modification, are permitted provided that the following conditions are met: 67 * 68 * 1. Redistributions of source code must retain the above copyright notice, 69 * this list of conditions and the following disclaimer. 70 * 71 * 2. Redistributions in binary form must reproduce the above copyright 72 * notice, this list of conditions and the following disclaimer in the 73 * documentation and/or other materials provided with the distribution. 74 * 75 * 3. Neither the name of the University nor the names of its contributors may 76 * be used to endorse or promote products derived from this software 77 * without specific prior written permission. 78 * 79 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 80 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 82 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 83 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 84 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 85 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 86 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 87 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 88 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 89 * POSSIBILITY OF SUCH DAMAGE. 90 * 91 * ---------------------------------------------------------------- 92 * 93 * Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan 94 * (Royal Institute of Technology, Stockholm, Sweden). 95 * All rights reserved. 96 * 97 * Redistribution and use in source and binary forms, with or without 98 * modification, are permitted provided that the following conditions 99 * are met: 100 * 101 * 1. Redistributions of source code must retain the above copyright 102 * notice, this list of conditions and the following disclaimer. 103 * 104 * 2. Redistributions in binary form must reproduce the above copyright 105 * notice, this list of conditions and the following disclaimer in the 106 * documentation and/or other materials provided with the distribution. 107 * 108 * 3. Neither the name of the Institute nor the names of its contributors 109 * may be used to endorse or promote products derived from this software 110 * without specific prior written permission. 111 * 112 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 113 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 114 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 115 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 116 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 117 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 118 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 119 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 120 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 121 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 122 * SUCH DAMAGE. 123 */ 124 125 /* 126 * XXXSRA We should omit this file entirely in Makefile.in via autoconf, 127 * but this will keep it from generating errors until that's written. 128 */ 129 130 #ifdef GSSAPI 131 132 /* 133 * XXXSRA Some of the following files are almost certainly unnecessary, 134 * but using this list (borrowed from gssapictx.c) gets rid of some 135 * whacky compilation errors when building with MSVC and should be 136 * harmless in any case. 137 */ 138 139 #include <config.h> 140 141 #include <stdlib.h> 142 #include <errno.h> 143 144 #include <isc/buffer.h> 145 #include <isc/dir.h> 146 #include <isc/entropy.h> 147 #include <isc/lex.h> 148 #include <isc/mem.h> 149 #include <isc/once.h> 150 #include <isc/random.h> 151 #include <isc/string.h> 152 #include <isc/time.h> 153 #include <isc/util.h> 154 155 #include <dns/fixedname.h> 156 #include <dns/name.h> 157 #include <dns/rdata.h> 158 #include <dns/rdataclass.h> 159 #include <dns/result.h> 160 #include <dns/types.h> 161 #include <dns/keyvalues.h> 162 #include <dns/log.h> 163 164 #include <dst/gssapi.h> 165 #include <dst/result.h> 166 167 #include "dst_internal.h" 168 169 /* 170 * The API we export 171 */ 172 #include "spnego.h" 173 174 /* asn1_err.h */ 175 /* Generated from ../../../lib/asn1/asn1_err.et */ 176 177 #ifndef ERROR_TABLE_BASE_asn1 178 /* these may be brought in already via gssapi_krb5.h */ 179 typedef enum asn1_error_number { 180 ASN1_BAD_TIMEFORMAT = 1859794432, 181 ASN1_MISSING_FIELD = 1859794433, 182 ASN1_MISPLACED_FIELD = 1859794434, 183 ASN1_TYPE_MISMATCH = 1859794435, 184 ASN1_OVERFLOW = 1859794436, 185 ASN1_OVERRUN = 1859794437, 186 ASN1_BAD_ID = 1859794438, 187 ASN1_BAD_LENGTH = 1859794439, 188 ASN1_BAD_FORMAT = 1859794440, 189 ASN1_PARSE_ERROR = 1859794441 190 } asn1_error_number; 191 192 #define ERROR_TABLE_BASE_asn1 1859794432 193 #endif 194 195 #define __asn1_common_definitions__ 196 197 typedef struct octet_string { 198 size_t length; 199 void *data; 200 } octet_string; 201 202 typedef char *general_string; 203 204 typedef char *utf8_string; 205 206 typedef struct oid { 207 size_t length; 208 unsigned *components; 209 } oid; 210 211 /* der.h */ 212 213 typedef enum { 214 ASN1_C_UNIV = 0, ASN1_C_APPL = 1, 215 ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3 216 } Der_class; 217 218 typedef enum { 219 PRIM = 0, CONS = 1 220 } Der_type; 221 222 /* Universal tags */ 223 224 enum { 225 UT_Boolean = 1, 226 UT_Integer = 2, 227 UT_BitString = 3, 228 UT_OctetString = 4, 229 UT_Null = 5, 230 UT_OID = 6, 231 UT_Enumerated = 10, 232 UT_Sequence = 16, 233 UT_Set = 17, 234 UT_PrintableString = 19, 235 UT_IA5String = 22, 236 UT_UTCTime = 23, 237 UT_GeneralizedTime = 24, 238 UT_VisibleString = 26, 239 UT_GeneralString = 27 240 }; 241 242 #define ASN1_INDEFINITE 0xdce0deed 243 244 static int 245 der_get_length(const unsigned char *p, size_t len, 246 size_t * val, size_t * size); 247 248 static int 249 der_get_octet_string(const unsigned char *p, size_t len, 250 octet_string * data, size_t * size); 251 static int 252 der_get_oid(const unsigned char *p, size_t len, 253 oid * data, size_t * size); 254 static int 255 der_get_tag(const unsigned char *p, size_t len, 256 Der_class * class, Der_type * type, 257 int *tag, size_t * size); 258 259 static int 260 der_match_tag(const unsigned char *p, size_t len, 261 Der_class class, Der_type type, 262 int tag, size_t * size); 263 static int 264 der_match_tag_and_length(const unsigned char *p, size_t len, 265 Der_class class, Der_type type, int tag, 266 size_t * length_ret, size_t * size); 267 268 static int 269 decode_oid(const unsigned char *p, size_t len, 270 oid * k, size_t * size); 271 272 static int 273 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size); 274 275 static int 276 decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *); 277 278 static int 279 der_put_int(unsigned char *p, size_t len, int val, size_t *); 280 281 static int 282 der_put_length(unsigned char *p, size_t len, size_t val, size_t *); 283 284 static int 285 der_put_octet_string(unsigned char *p, size_t len, 286 const octet_string * data, size_t *); 287 static int 288 der_put_oid(unsigned char *p, size_t len, 289 const oid * data, size_t * size); 290 static int 291 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, 292 int tag, size_t *); 293 static int 294 der_put_length_and_tag(unsigned char *, size_t, size_t, 295 Der_class, Der_type, int, size_t *); 296 297 static int 298 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *); 299 300 static int 301 encode_octet_string(unsigned char *p, size_t len, 302 const octet_string * k, size_t *); 303 static int 304 encode_oid(unsigned char *p, size_t len, 305 const oid * k, size_t *); 306 307 static void 308 free_octet_string(octet_string * k); 309 310 static void 311 free_oid (oid * k); 312 313 static size_t 314 length_len(size_t len); 315 316 static int 317 fix_dce(size_t reallen, size_t * len); 318 319 /* 320 * Include stuff generated by the ASN.1 compiler. 321 */ 322 323 #include "spnego_asn1.c" 324 325 static unsigned char gss_krb5_mech_oid_bytes[] = { 326 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 327 }; 328 329 static gss_OID_desc gss_krb5_mech_oid_desc = { 330 sizeof(gss_krb5_mech_oid_bytes), 331 gss_krb5_mech_oid_bytes 332 }; 333 334 static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc; 335 336 static unsigned char gss_mskrb5_mech_oid_bytes[] = { 337 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02 338 }; 339 340 static gss_OID_desc gss_mskrb5_mech_oid_desc = { 341 sizeof(gss_mskrb5_mech_oid_bytes), 342 gss_mskrb5_mech_oid_bytes 343 }; 344 345 static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc; 346 347 static unsigned char gss_spnego_mech_oid_bytes[] = { 348 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 349 }; 350 351 static gss_OID_desc gss_spnego_mech_oid_desc = { 352 sizeof(gss_spnego_mech_oid_bytes), 353 gss_spnego_mech_oid_bytes 354 }; 355 356 static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc; 357 358 /* spnegokrb5_locl.h */ 359 360 static OM_uint32 361 gssapi_spnego_encapsulate(OM_uint32 *, 362 unsigned char *, 363 size_t, 364 gss_buffer_t, 365 const gss_OID); 366 367 static OM_uint32 368 gssapi_spnego_decapsulate(OM_uint32 *, 369 gss_buffer_t, 370 unsigned char **, 371 size_t *, 372 const gss_OID); 373 374 /* mod_auth_kerb.c */ 375 376 static int 377 cmp_gss_type(gss_buffer_t token, gss_OID oid) 378 { 379 unsigned char *p; 380 size_t len; 381 382 if (token->length == 0U) 383 return (GSS_S_DEFECTIVE_TOKEN); 384 385 p = token->value; 386 if (*p++ != 0x60) 387 return (GSS_S_DEFECTIVE_TOKEN); 388 len = *p++; 389 if (len & 0x80) { 390 if ((len & 0x7f) > 4U) 391 return (GSS_S_DEFECTIVE_TOKEN); 392 p += len & 0x7f; 393 } 394 if (*p++ != 0x06) 395 return (GSS_S_DEFECTIVE_TOKEN); 396 397 if (((OM_uint32) *p++) != oid->length) 398 return (GSS_S_DEFECTIVE_TOKEN); 399 400 return (memcmp(p, oid->elements, oid->length)); 401 } 402 403 /* accept_sec_context.c */ 404 /* 405 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly 406 * based on Heimdal code) 407 */ 408 409 static OM_uint32 410 code_NegTokenArg(OM_uint32 * minor_status, 411 const NegTokenResp * resp, 412 unsigned char **outbuf, 413 size_t * outbuf_size) 414 { 415 OM_uint32 ret; 416 u_char *buf; 417 size_t buf_size, buf_len = 0; 418 419 buf_size = 1024; 420 buf = malloc(buf_size); 421 if (buf == NULL) { 422 *minor_status = ENOMEM; 423 return (GSS_S_FAILURE); 424 } 425 do { 426 ret = encode_NegTokenResp(buf + buf_size - 1, 427 buf_size, 428 resp, &buf_len); 429 if (ret == 0) { 430 size_t tmp; 431 432 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, 433 buf_size - buf_len, 434 buf_len, 435 ASN1_C_CONTEXT, 436 CONS, 437 1, 438 &tmp); 439 if (ret == 0) 440 buf_len += tmp; 441 } 442 if (ret) { 443 if (ret == ASN1_OVERFLOW) { 444 u_char *tmp; 445 446 buf_size *= 2; 447 tmp = realloc(buf, buf_size); 448 if (tmp == NULL) { 449 *minor_status = ENOMEM; 450 free(buf); 451 return (GSS_S_FAILURE); 452 } 453 buf = tmp; 454 } else { 455 *minor_status = ret; 456 free(buf); 457 return (GSS_S_FAILURE); 458 } 459 } 460 } while (ret == ASN1_OVERFLOW); 461 462 *outbuf = malloc(buf_len); 463 if (*outbuf == NULL) { 464 *minor_status = ENOMEM; 465 free(buf); 466 return (GSS_S_FAILURE); 467 } 468 memmove(*outbuf, buf + buf_size - buf_len, buf_len); 469 *outbuf_size = buf_len; 470 471 free(buf); 472 473 return (GSS_S_COMPLETE); 474 } 475 476 static OM_uint32 477 send_reject(OM_uint32 * minor_status, 478 gss_buffer_t output_token) 479 { 480 NegTokenResp resp; 481 OM_uint32 ret; 482 483 resp.negState = malloc(sizeof(*resp.negState)); 484 if (resp.negState == NULL) { 485 *minor_status = ENOMEM; 486 return (GSS_S_FAILURE); 487 } 488 *(resp.negState) = reject; 489 490 resp.supportedMech = NULL; 491 resp.responseToken = NULL; 492 resp.mechListMIC = NULL; 493 494 ret = code_NegTokenArg(minor_status, &resp, 495 (unsigned char **)&output_token->value, 496 &output_token->length); 497 free_NegTokenResp(&resp); 498 if (ret) 499 return (ret); 500 501 return (GSS_S_BAD_MECH); 502 } 503 504 static OM_uint32 505 send_accept(OM_uint32 * minor_status, 506 gss_buffer_t output_token, 507 gss_buffer_t mech_token, 508 const gss_OID pref) 509 { 510 NegTokenResp resp; 511 OM_uint32 ret; 512 513 memset(&resp, 0, sizeof(resp)); 514 resp.negState = malloc(sizeof(*resp.negState)); 515 if (resp.negState == NULL) { 516 *minor_status = ENOMEM; 517 return (GSS_S_FAILURE); 518 } 519 *(resp.negState) = accept_completed; 520 521 resp.supportedMech = malloc(sizeof(*resp.supportedMech)); 522 if (resp.supportedMech == NULL) { 523 free_NegTokenResp(&resp); 524 *minor_status = ENOMEM; 525 return (GSS_S_FAILURE); 526 } 527 ret = der_get_oid(pref->elements, 528 pref->length, 529 resp.supportedMech, 530 NULL); 531 if (ret) { 532 free_NegTokenResp(&resp); 533 *minor_status = ENOMEM; 534 return (GSS_S_FAILURE); 535 } 536 if (mech_token != NULL && mech_token->length != 0U) { 537 resp.responseToken = malloc(sizeof(*resp.responseToken)); 538 if (resp.responseToken == NULL) { 539 free_NegTokenResp(&resp); 540 *minor_status = ENOMEM; 541 return (GSS_S_FAILURE); 542 } 543 resp.responseToken->length = mech_token->length; 544 resp.responseToken->data = mech_token->value; 545 } 546 547 ret = code_NegTokenArg(minor_status, &resp, 548 (unsigned char **)&output_token->value, 549 &output_token->length); 550 if (resp.responseToken != NULL) { 551 free(resp.responseToken); 552 resp.responseToken = NULL; 553 } 554 free_NegTokenResp(&resp); 555 if (ret) 556 return (ret); 557 558 return (GSS_S_COMPLETE); 559 } 560 561 OM_uint32 562 gss_accept_sec_context_spnego(OM_uint32 *minor_status, 563 gss_ctx_id_t *context_handle, 564 const gss_cred_id_t acceptor_cred_handle, 565 const gss_buffer_t input_token_buffer, 566 const gss_channel_bindings_t input_chan_bindings, 567 gss_name_t *src_name, 568 gss_OID *mech_type, 569 gss_buffer_t output_token, 570 OM_uint32 *ret_flags, 571 OM_uint32 *time_rec, 572 gss_cred_id_t *delegated_cred_handle) 573 { 574 NegTokenInit init_token; 575 OM_uint32 major_status; 576 OM_uint32 minor_status2; 577 gss_buffer_desc ibuf, obuf; 578 gss_buffer_t ot = NULL; 579 gss_OID pref = GSS_KRB5_MECH; 580 unsigned char *buf; 581 size_t buf_size; 582 size_t len, taglen, ni_len; 583 int found = 0; 584 int ret; 585 unsigned i; 586 587 /* 588 * Before doing anything else, see whether this is a SPNEGO 589 * PDU. If not, dispatch to the GSSAPI library and get out. 590 */ 591 592 if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH)) 593 return (gss_accept_sec_context(minor_status, 594 context_handle, 595 acceptor_cred_handle, 596 input_token_buffer, 597 input_chan_bindings, 598 src_name, 599 mech_type, 600 output_token, 601 ret_flags, 602 time_rec, 603 delegated_cred_handle)); 604 605 /* 606 * If we get here, it's SPNEGO. 607 */ 608 609 memset(&init_token, 0, sizeof(init_token)); 610 611 ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer, 612 &buf, &buf_size, GSS_SPNEGO_MECH); 613 if (ret) 614 return (ret); 615 616 ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS, 617 0, &len, &taglen); 618 if (ret) 619 return (ret); 620 621 ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len); 622 if (ret) { 623 *minor_status = EINVAL; /* XXX */ 624 return (GSS_S_DEFECTIVE_TOKEN); 625 } 626 627 for (i = 0; !found && i < init_token.mechTypes.len; ++i) { 628 unsigned char mechbuf[17]; 629 size_t mech_len; 630 631 ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1, 632 sizeof(mechbuf), 633 &init_token.mechTypes.val[i], 634 &mech_len); 635 if (ret) { 636 free_NegTokenInit(&init_token); 637 return (GSS_S_DEFECTIVE_TOKEN); 638 } 639 if (mech_len == GSS_KRB5_MECH->length && 640 memcmp(GSS_KRB5_MECH->elements, 641 mechbuf + sizeof(mechbuf) - mech_len, 642 mech_len) == 0) { 643 found = 1; 644 break; 645 } 646 if (mech_len == GSS_MSKRB5_MECH->length && 647 memcmp(GSS_MSKRB5_MECH->elements, 648 mechbuf + sizeof(mechbuf) - mech_len, 649 mech_len) == 0) { 650 found = 1; 651 if (i == 0) 652 pref = GSS_MSKRB5_MECH; 653 break; 654 } 655 } 656 657 if (!found) { 658 free_NegTokenInit(&init_token); 659 return (send_reject(minor_status, output_token)); 660 } 661 662 if (i == 0 && init_token.mechToken != NULL) { 663 ibuf.length = init_token.mechToken->length; 664 ibuf.value = init_token.mechToken->data; 665 666 major_status = gss_accept_sec_context(minor_status, 667 context_handle, 668 acceptor_cred_handle, 669 &ibuf, 670 input_chan_bindings, 671 src_name, 672 mech_type, 673 &obuf, 674 ret_flags, 675 time_rec, 676 delegated_cred_handle); 677 if (GSS_ERROR(major_status)) { 678 free_NegTokenInit(&init_token); 679 send_reject(&minor_status2, output_token); 680 return (major_status); 681 } 682 ot = &obuf; 683 } 684 ret = send_accept(&minor_status2, output_token, ot, pref); 685 free_NegTokenInit(&init_token); 686 if (ot != NULL && ot->length != 0U) 687 gss_release_buffer(&minor_status2, ot); 688 689 return (ret); 690 } 691 692 /* decapsulate.c */ 693 694 static OM_uint32 695 gssapi_verify_mech_header(u_char ** str, 696 size_t total_len, 697 const gss_OID mech) 698 { 699 size_t len, len_len, mech_len, foo; 700 int e; 701 u_char *p = *str; 702 703 if (total_len < 1U) 704 return (GSS_S_DEFECTIVE_TOKEN); 705 if (*p++ != 0x60) 706 return (GSS_S_DEFECTIVE_TOKEN); 707 e = der_get_length(p, total_len - 1, &len, &len_len); 708 if (e || 1 + len_len + len != total_len) 709 return (GSS_S_DEFECTIVE_TOKEN); 710 p += len_len; 711 if (*p++ != 0x06) 712 return (GSS_S_DEFECTIVE_TOKEN); 713 e = der_get_length(p, total_len - 1 - len_len - 1, 714 &mech_len, &foo); 715 if (e) 716 return (GSS_S_DEFECTIVE_TOKEN); 717 p += foo; 718 if (mech_len != mech->length) 719 return (GSS_S_BAD_MECH); 720 if (memcmp(p, mech->elements, mech->length) != 0) 721 return (GSS_S_BAD_MECH); 722 p += mech_len; 723 *str = p; 724 return (GSS_S_COMPLETE); 725 } 726 727 /* 728 * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does 729 * not copy data, so just free `in_token'. 730 */ 731 732 static OM_uint32 733 gssapi_spnego_decapsulate(OM_uint32 *minor_status, 734 gss_buffer_t input_token_buffer, 735 unsigned char **buf, 736 size_t *buf_len, 737 const gss_OID mech) 738 { 739 u_char *p; 740 OM_uint32 ret; 741 742 p = input_token_buffer->value; 743 ret = gssapi_verify_mech_header(&p, 744 input_token_buffer->length, 745 mech); 746 if (ret) { 747 *minor_status = ret; 748 return (GSS_S_FAILURE); 749 } 750 *buf_len = input_token_buffer->length - 751 (p - (u_char *) input_token_buffer->value); 752 *buf = p; 753 return (GSS_S_COMPLETE); 754 } 755 756 /* der_free.c */ 757 758 static void 759 free_octet_string(octet_string *k) 760 { 761 free(k->data); 762 k->data = NULL; 763 } 764 765 static void 766 free_oid(oid *k) 767 { 768 free(k->components); 769 k->components = NULL; 770 } 771 772 /* der_get.c */ 773 774 /* 775 * All decoding functions take a pointer `p' to first position in which to 776 * read, from the left, `len' which means the maximum number of characters we 777 * are able to read, `ret' were the value will be returned and `size' where 778 * the number of used bytes is stored. Either 0 or an error code is returned. 779 */ 780 781 static int 782 der_get_unsigned(const unsigned char *p, size_t len, 783 unsigned *ret, size_t *size) 784 { 785 unsigned val = 0; 786 size_t oldlen = len; 787 788 while (len--) 789 val = val * 256 + *p++; 790 *ret = val; 791 if (size) 792 *size = oldlen; 793 return (0); 794 } 795 796 static int 797 der_get_int(const unsigned char *p, size_t len, 798 int *ret, size_t *size) 799 { 800 int val = 0; 801 size_t oldlen = len; 802 803 if (len > 0U) { 804 val = (signed char)*p++; 805 while (--len) 806 val = val * 256 + *p++; 807 } 808 *ret = val; 809 if (size) 810 *size = oldlen; 811 return (0); 812 } 813 814 static int 815 der_get_length(const unsigned char *p, size_t len, 816 size_t *val, size_t *size) 817 { 818 size_t v; 819 820 if (len <= 0U) 821 return (ASN1_OVERRUN); 822 --len; 823 v = *p++; 824 if (v < 128U) { 825 *val = v; 826 if (size) 827 *size = 1; 828 } else { 829 int e; 830 size_t l; 831 unsigned tmp; 832 833 if (v == 0x80U) { 834 *val = ASN1_INDEFINITE; 835 if (size) 836 *size = 1; 837 return (0); 838 } 839 v &= 0x7F; 840 if (len < v) 841 return (ASN1_OVERRUN); 842 e = der_get_unsigned(p, v, &tmp, &l); 843 if (e) 844 return (e); 845 *val = tmp; 846 if (size) 847 *size = l + 1; 848 } 849 return (0); 850 } 851 852 static int 853 der_get_octet_string(const unsigned char *p, size_t len, 854 octet_string *data, size_t *size) 855 { 856 data->length = len; 857 if (len != 0U) { 858 data->data = malloc(len); 859 if (data->data == NULL) 860 return (ENOMEM); 861 memmove(data->data, p, len); 862 } else 863 data->data = NULL; 864 if (size) 865 *size = len; 866 return (0); 867 } 868 869 static int 870 der_get_oid(const unsigned char *p, size_t len, 871 oid *data, size_t *size) 872 { 873 int n; 874 size_t oldlen = len; 875 876 data->components = NULL; 877 data->length = 0; 878 if (len < 1U) 879 return (ASN1_OVERRUN); 880 881 data->components = malloc(len * sizeof(*data->components)); 882 if (data->components == NULL && len != 0U) 883 return (ENOMEM); 884 data->components[0] = (*p) / 40; 885 data->components[1] = (*p) % 40; 886 --len; 887 ++p; 888 for (n = 2; len > 0U; ++n) { 889 unsigned u = 0; 890 891 do { 892 --len; 893 u = u * 128 + (*p++ % 128); 894 } while (len > 0U && p[-1] & 0x80); 895 data->components[n] = u; 896 } 897 if (p[-1] & 0x80) { 898 free_oid(data); 899 return (ASN1_OVERRUN); 900 } 901 data->length = n; 902 if (size) 903 *size = oldlen; 904 return (0); 905 } 906 907 static int 908 der_get_tag(const unsigned char *p, size_t len, 909 Der_class *class, Der_type *type, 910 int *tag, size_t *size) 911 { 912 if (len < 1U) 913 return (ASN1_OVERRUN); 914 *class = (Der_class) (((*p) >> 6) & 0x03); 915 *type = (Der_type) (((*p) >> 5) & 0x01); 916 *tag = (*p) & 0x1F; 917 if (size) 918 *size = 1; 919 return (0); 920 } 921 922 static int 923 der_match_tag(const unsigned char *p, size_t len, 924 Der_class class, Der_type type, 925 int tag, size_t *size) 926 { 927 size_t l; 928 Der_class thisclass; 929 Der_type thistype; 930 int thistag; 931 int e; 932 933 e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l); 934 if (e) 935 return (e); 936 if (class != thisclass || type != thistype) 937 return (ASN1_BAD_ID); 938 if (tag > thistag) 939 return (ASN1_MISPLACED_FIELD); 940 if (tag < thistag) 941 return (ASN1_MISSING_FIELD); 942 if (size) 943 *size = l; 944 return (0); 945 } 946 947 static int 948 der_match_tag_and_length(const unsigned char *p, size_t len, 949 Der_class class, Der_type type, int tag, 950 size_t *length_ret, size_t *size) 951 { 952 size_t l, ret = 0; 953 int e; 954 955 e = der_match_tag(p, len, class, type, tag, &l); 956 if (e) 957 return (e); 958 p += l; 959 len -= l; 960 ret += l; 961 e = der_get_length(p, len, length_ret, &l); 962 if (e) 963 return (e); 964 /* p += l; */ 965 len -= l; 966 POST(len); 967 ret += l; 968 if (size) 969 *size = ret; 970 return (0); 971 } 972 973 static int 974 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size) 975 { 976 size_t ret = 0; 977 size_t l, reallen; 978 int e; 979 980 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); 981 if (e) 982 return (e); 983 p += l; 984 len -= l; 985 ret += l; 986 e = der_get_length(p, len, &reallen, &l); 987 if (e) 988 return (e); 989 p += l; 990 len -= l; 991 ret += l; 992 e = der_get_int(p, reallen, num, &l); 993 if (e) 994 return (e); 995 p += l; 996 len -= l; 997 POST(p); POST(len); 998 ret += l; 999 if (size) 1000 *size = ret; 1001 return (0); 1002 } 1003 1004 static int 1005 decode_octet_string(const unsigned char *p, size_t len, 1006 octet_string *k, size_t *size) 1007 { 1008 size_t ret = 0; 1009 size_t l; 1010 int e; 1011 size_t slen; 1012 1013 k->data = NULL; 1014 k->length = 0; 1015 1016 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l); 1017 if (e) 1018 return (e); 1019 p += l; 1020 len -= l; 1021 ret += l; 1022 1023 e = der_get_length(p, len, &slen, &l); 1024 if (e) 1025 return (e); 1026 p += l; 1027 len -= l; 1028 ret += l; 1029 if (len < slen) 1030 return (ASN1_OVERRUN); 1031 1032 e = der_get_octet_string(p, slen, k, &l); 1033 if (e) 1034 return (e); 1035 p += l; 1036 len -= l; 1037 POST(p); POST(len); 1038 ret += l; 1039 if (size) 1040 *size = ret; 1041 return (0); 1042 } 1043 1044 static int 1045 decode_oid(const unsigned char *p, size_t len, 1046 oid *k, size_t *size) 1047 { 1048 size_t ret = 0; 1049 size_t l; 1050 int e; 1051 size_t slen; 1052 1053 e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l); 1054 if (e) 1055 return (e); 1056 p += l; 1057 len -= l; 1058 ret += l; 1059 1060 e = der_get_length(p, len, &slen, &l); 1061 if (e) 1062 return (e); 1063 p += l; 1064 len -= l; 1065 ret += l; 1066 if (len < slen) 1067 return (ASN1_OVERRUN); 1068 1069 e = der_get_oid(p, slen, k, &l); 1070 if (e) 1071 return (e); 1072 p += l; 1073 len -= l; 1074 POST(p); POST(len); 1075 ret += l; 1076 if (size) 1077 *size = ret; 1078 return (0); 1079 } 1080 1081 static int 1082 fix_dce(size_t reallen, size_t *len) 1083 { 1084 if (reallen == ASN1_INDEFINITE) 1085 return (1); 1086 if (*len < reallen) 1087 return (-1); 1088 *len = reallen; 1089 return (0); 1090 } 1091 1092 /* der_length.c */ 1093 1094 static size_t 1095 len_unsigned(unsigned val) 1096 { 1097 size_t ret = 0; 1098 1099 do { 1100 ++ret; 1101 val /= 256; 1102 } while (val); 1103 return (ret); 1104 } 1105 1106 static size_t 1107 length_len(size_t len) 1108 { 1109 if (len < 128U) 1110 return (1); 1111 else 1112 return (len_unsigned((unsigned int)len) + 1); 1113 } 1114 1115 1116 /* der_put.c */ 1117 1118 /* 1119 * All encoding functions take a pointer `p' to first position in which to 1120 * write, from the right, `len' which means the maximum number of characters 1121 * we are able to write. The function returns the number of characters 1122 * written in `size' (if non-NULL). The return value is 0 or an error. 1123 */ 1124 1125 static int 1126 der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size) 1127 { 1128 unsigned char *base = p; 1129 1130 if (val) { 1131 while (len > 0U && val) { 1132 *p-- = val % 256; 1133 val /= 256; 1134 --len; 1135 } 1136 if (val != 0) 1137 return (ASN1_OVERFLOW); 1138 else { 1139 *size = base - p; 1140 return (0); 1141 } 1142 } else if (len < 1U) 1143 return (ASN1_OVERFLOW); 1144 else { 1145 *p = 0; 1146 *size = 1; 1147 return (0); 1148 } 1149 } 1150 1151 static int 1152 der_put_int(unsigned char *p, size_t len, int val, size_t *size) 1153 { 1154 unsigned char *base = p; 1155 1156 if (val >= 0) { 1157 do { 1158 if (len < 1U) 1159 return (ASN1_OVERFLOW); 1160 *p-- = val % 256; 1161 len--; 1162 val /= 256; 1163 } while (val); 1164 if (p[1] >= 128) { 1165 if (len < 1U) 1166 return (ASN1_OVERFLOW); 1167 *p-- = 0; 1168 len--; 1169 } 1170 } else { 1171 val = ~val; 1172 do { 1173 if (len < 1U) 1174 return (ASN1_OVERFLOW); 1175 *p-- = ~(val % 256); 1176 len--; 1177 val /= 256; 1178 } while (val); 1179 if (p[1] < 128) { 1180 if (len < 1U) 1181 return (ASN1_OVERFLOW); 1182 *p-- = 0xff; 1183 len--; 1184 } 1185 } 1186 *size = base - p; 1187 return (0); 1188 } 1189 1190 static int 1191 der_put_length(unsigned char *p, size_t len, size_t val, size_t *size) 1192 { 1193 if (len < 1U) 1194 return (ASN1_OVERFLOW); 1195 if (val < 128U) { 1196 *p = (unsigned char)val; 1197 *size = 1; 1198 return (0); 1199 } else { 1200 size_t l; 1201 int e; 1202 1203 e = der_put_unsigned(p, len - 1, (unsigned int)val, &l); 1204 if (e) 1205 return (e); 1206 p -= l; 1207 *p = 0x80 | (unsigned char)l; 1208 *size = l + 1; 1209 return (0); 1210 } 1211 } 1212 1213 static int 1214 der_put_octet_string(unsigned char *p, size_t len, 1215 const octet_string *data, size_t *size) 1216 { 1217 if (len < data->length) 1218 return (ASN1_OVERFLOW); 1219 p -= data->length; 1220 len -= data->length; 1221 POST(len); 1222 memmove(p + 1, data->data, data->length); 1223 *size = data->length; 1224 return (0); 1225 } 1226 1227 static int 1228 der_put_oid(unsigned char *p, size_t len, 1229 const oid *data, size_t *size) 1230 { 1231 unsigned char *base = p; 1232 size_t n; 1233 1234 for (n = data->length; n >= 3u; --n) { 1235 unsigned u = data->components[n - 1]; 1236 1237 if (len < 1U) 1238 return (ASN1_OVERFLOW); 1239 *p-- = u % 128; 1240 u /= 128; 1241 --len; 1242 while (u > 0) { 1243 if (len < 1U) 1244 return (ASN1_OVERFLOW); 1245 *p-- = 128 + u % 128; 1246 u /= 128; 1247 --len; 1248 } 1249 } 1250 if (len < 1U) 1251 return (ASN1_OVERFLOW); 1252 *p-- = 40 * data->components[0] + data->components[1]; 1253 *size = base - p; 1254 return (0); 1255 } 1256 1257 static int 1258 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, 1259 int tag, size_t *size) 1260 { 1261 if (len < 1U) 1262 return (ASN1_OVERFLOW); 1263 *p = (class << 6) | (type << 5) | tag; /* XXX */ 1264 *size = 1; 1265 return (0); 1266 } 1267 1268 static int 1269 der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val, 1270 Der_class class, Der_type type, int tag, size_t *size) 1271 { 1272 size_t ret = 0; 1273 size_t l; 1274 int e; 1275 1276 e = der_put_length(p, len, len_val, &l); 1277 if (e) 1278 return (e); 1279 p -= l; 1280 len -= l; 1281 ret += l; 1282 e = der_put_tag(p, len, class, type, tag, &l); 1283 if (e) 1284 return (e); 1285 p -= l; 1286 len -= l; 1287 POST(p); POST(len); 1288 ret += l; 1289 *size = ret; 1290 return (0); 1291 } 1292 1293 static int 1294 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size) 1295 { 1296 unsigned num = *(const unsigned *)data; 1297 size_t ret = 0; 1298 size_t l; 1299 int e; 1300 1301 e = der_put_int(p, len, num, &l); 1302 if (e) 1303 return (e); 1304 p -= l; 1305 len -= l; 1306 ret += l; 1307 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); 1308 if (e) 1309 return (e); 1310 p -= l; 1311 len -= l; 1312 POST(p); POST(len); 1313 ret += l; 1314 *size = ret; 1315 return (0); 1316 } 1317 1318 static int 1319 encode_octet_string(unsigned char *p, size_t len, 1320 const octet_string *k, size_t *size) 1321 { 1322 size_t ret = 0; 1323 size_t l; 1324 int e; 1325 1326 e = der_put_octet_string(p, len, k, &l); 1327 if (e) 1328 return (e); 1329 p -= l; 1330 len -= l; 1331 ret += l; 1332 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l); 1333 if (e) 1334 return (e); 1335 p -= l; 1336 len -= l; 1337 POST(p); POST(len); 1338 ret += l; 1339 *size = ret; 1340 return (0); 1341 } 1342 1343 static int 1344 encode_oid(unsigned char *p, size_t len, 1345 const oid *k, size_t *size) 1346 { 1347 size_t ret = 0; 1348 size_t l; 1349 int e; 1350 1351 e = der_put_oid(p, len, k, &l); 1352 if (e) 1353 return (e); 1354 p -= l; 1355 len -= l; 1356 ret += l; 1357 e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l); 1358 if (e) 1359 return (e); 1360 p -= l; 1361 len -= l; 1362 POST(p); POST(len); 1363 ret += l; 1364 *size = ret; 1365 return (0); 1366 } 1367 1368 1369 /* encapsulate.c */ 1370 1371 static void 1372 gssapi_encap_length(size_t data_len, 1373 size_t *len, 1374 size_t *total_len, 1375 const gss_OID mech) 1376 { 1377 size_t len_len; 1378 1379 *len = 1 + 1 + mech->length + data_len; 1380 1381 len_len = length_len(*len); 1382 1383 *total_len = 1 + len_len + *len; 1384 } 1385 1386 static u_char * 1387 gssapi_mech_make_header(u_char *p, 1388 size_t len, 1389 const gss_OID mech) 1390 { 1391 int e; 1392 size_t len_len, foo; 1393 1394 *p++ = 0x60; 1395 len_len = length_len(len); 1396 e = der_put_length(p + len_len - 1, len_len, len, &foo); 1397 if (e || foo != len_len) 1398 return (NULL); 1399 p += len_len; 1400 *p++ = 0x06; 1401 *p++ = mech->length; 1402 memmove(p, mech->elements, mech->length); 1403 p += mech->length; 1404 return (p); 1405 } 1406 1407 /* 1408 * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. 1409 */ 1410 1411 static OM_uint32 1412 gssapi_spnego_encapsulate(OM_uint32 * minor_status, 1413 unsigned char *buf, 1414 size_t buf_size, 1415 gss_buffer_t output_token, 1416 const gss_OID mech) 1417 { 1418 size_t len, outer_len; 1419 u_char *p; 1420 1421 gssapi_encap_length(buf_size, &len, &outer_len, mech); 1422 1423 output_token->length = outer_len; 1424 output_token->value = malloc(outer_len); 1425 if (output_token->value == NULL) { 1426 *minor_status = ENOMEM; 1427 return (GSS_S_FAILURE); 1428 } 1429 p = gssapi_mech_make_header(output_token->value, len, mech); 1430 if (p == NULL) { 1431 if (output_token->length != 0U) 1432 gss_release_buffer(minor_status, output_token); 1433 return (GSS_S_FAILURE); 1434 } 1435 memmove(p, buf, buf_size); 1436 return (GSS_S_COMPLETE); 1437 } 1438 1439 /* init_sec_context.c */ 1440 /* 1441 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly 1442 * based on Heimdal code) 1443 */ 1444 1445 static int 1446 add_mech(MechTypeList * mech_list, gss_OID mech) 1447 { 1448 MechType *tmp; 1449 int ret; 1450 1451 tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp)); 1452 if (tmp == NULL) 1453 return (ENOMEM); 1454 mech_list->val = tmp; 1455 1456 ret = der_get_oid(mech->elements, mech->length, 1457 &mech_list->val[mech_list->len], NULL); 1458 if (ret) 1459 return (ret); 1460 1461 mech_list->len++; 1462 return (0); 1463 } 1464 1465 /* 1466 * return the length of the mechanism in token or -1 1467 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN 1468 */ 1469 1470 static ssize_t 1471 gssapi_krb5_get_mech(const u_char *ptr, 1472 size_t total_len, 1473 const u_char **mech_ret) 1474 { 1475 size_t len, len_len, mech_len, foo; 1476 const u_char *p = ptr; 1477 int e; 1478 1479 if (total_len < 1U) 1480 return (-1); 1481 if (*p++ != 0x60) 1482 return (-1); 1483 e = der_get_length (p, total_len - 1, &len, &len_len); 1484 if (e || 1 + len_len + len != total_len) 1485 return (-1); 1486 p += len_len; 1487 if (*p++ != 0x06) 1488 return (-1); 1489 e = der_get_length (p, total_len - 1 - len_len - 1, 1490 &mech_len, &foo); 1491 if (e) 1492 return (-1); 1493 p += foo; 1494 *mech_ret = p; 1495 return (mech_len); 1496 } 1497 1498 static OM_uint32 1499 spnego_initial(OM_uint32 *minor_status, 1500 const gss_cred_id_t initiator_cred_handle, 1501 gss_ctx_id_t *context_handle, 1502 const gss_name_t target_name, 1503 const gss_OID mech_type, 1504 OM_uint32 req_flags, 1505 OM_uint32 time_req, 1506 const gss_channel_bindings_t input_chan_bindings, 1507 const gss_buffer_t input_token, 1508 gss_OID *actual_mech_type, 1509 gss_buffer_t output_token, 1510 OM_uint32 *ret_flags, 1511 OM_uint32 *time_rec) 1512 { 1513 NegTokenInit token_init; 1514 OM_uint32 major_status, minor_status2; 1515 gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER; 1516 unsigned char *buf = NULL; 1517 size_t buf_size; 1518 size_t len; 1519 int ret; 1520 1521 (void)mech_type; 1522 1523 memset(&token_init, 0, sizeof(token_init)); 1524 1525 ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH); 1526 if (ret) { 1527 *minor_status = ret; 1528 ret = GSS_S_FAILURE; 1529 goto end; 1530 } 1531 1532 major_status = gss_init_sec_context(minor_status, 1533 initiator_cred_handle, 1534 context_handle, 1535 target_name, 1536 GSS_KRB5_MECH, 1537 req_flags, 1538 time_req, 1539 input_chan_bindings, 1540 input_token, 1541 actual_mech_type, 1542 &krb5_output_token, 1543 ret_flags, 1544 time_rec); 1545 if (GSS_ERROR(major_status)) { 1546 ret = major_status; 1547 goto end; 1548 } 1549 if (krb5_output_token.length > 0U) { 1550 token_init.mechToken = malloc(sizeof(*token_init.mechToken)); 1551 if (token_init.mechToken == NULL) { 1552 *minor_status = ENOMEM; 1553 ret = GSS_S_FAILURE; 1554 goto end; 1555 } 1556 token_init.mechToken->data = krb5_output_token.value; 1557 token_init.mechToken->length = krb5_output_token.length; 1558 } 1559 /* 1560 * The MS implementation of SPNEGO seems to not like the mechListMIC 1561 * field, so we omit it (it's optional anyway) 1562 */ 1563 1564 buf_size = 1024; 1565 buf = malloc(buf_size); 1566 if (buf == NULL) { 1567 *minor_status = ENOMEM; 1568 ret = GSS_S_FAILURE; 1569 goto end; 1570 } 1571 1572 do { 1573 ret = encode_NegTokenInit(buf + buf_size - 1, 1574 buf_size, 1575 &token_init, &len); 1576 if (ret == 0) { 1577 size_t tmp; 1578 1579 ret = der_put_length_and_tag(buf + buf_size - len - 1, 1580 buf_size - len, 1581 len, 1582 ASN1_C_CONTEXT, 1583 CONS, 1584 0, 1585 &tmp); 1586 if (ret == 0) 1587 len += tmp; 1588 } 1589 if (ret) { 1590 if (ret == ASN1_OVERFLOW) { 1591 u_char *tmp; 1592 1593 buf_size *= 2; 1594 tmp = realloc(buf, buf_size); 1595 if (tmp == NULL) { 1596 *minor_status = ENOMEM; 1597 ret = GSS_S_FAILURE; 1598 goto end; 1599 } 1600 buf = tmp; 1601 } else { 1602 *minor_status = ret; 1603 ret = GSS_S_FAILURE; 1604 goto end; 1605 } 1606 } 1607 } while (ret == ASN1_OVERFLOW); 1608 1609 ret = gssapi_spnego_encapsulate(minor_status, 1610 buf + buf_size - len, len, 1611 output_token, GSS_SPNEGO_MECH); 1612 if (ret == GSS_S_COMPLETE) 1613 ret = major_status; 1614 1615 end: 1616 if (token_init.mechToken != NULL) { 1617 free(token_init.mechToken); 1618 token_init.mechToken = NULL; 1619 } 1620 free_NegTokenInit(&token_init); 1621 if (krb5_output_token.length != 0U) 1622 gss_release_buffer(&minor_status2, &krb5_output_token); 1623 if (buf) 1624 free(buf); 1625 1626 return (ret); 1627 } 1628 1629 static OM_uint32 1630 spnego_reply(OM_uint32 *minor_status, 1631 const gss_cred_id_t initiator_cred_handle, 1632 gss_ctx_id_t *context_handle, 1633 const gss_name_t target_name, 1634 const gss_OID mech_type, 1635 OM_uint32 req_flags, 1636 OM_uint32 time_req, 1637 const gss_channel_bindings_t input_chan_bindings, 1638 const gss_buffer_t input_token, 1639 gss_OID *actual_mech_type, 1640 gss_buffer_t output_token, 1641 OM_uint32 *ret_flags, 1642 OM_uint32 *time_rec) 1643 { 1644 OM_uint32 ret; 1645 NegTokenResp resp; 1646 unsigned char *buf; 1647 size_t buf_size; 1648 u_char oidbuf[17]; 1649 size_t oidlen; 1650 gss_buffer_desc sub_token; 1651 ssize_t mech_len; 1652 const u_char *p; 1653 size_t len, taglen; 1654 1655 (void)mech_type; 1656 1657 output_token->length = 0; 1658 output_token->value = NULL; 1659 1660 /* 1661 * SPNEGO doesn't include gss wrapping on SubsequentContextToken 1662 * like the Kerberos 5 mech does. But lets check for it anyway. 1663 */ 1664 1665 mech_len = gssapi_krb5_get_mech(input_token->value, 1666 input_token->length, 1667 &p); 1668 1669 if (mech_len < 0) { 1670 buf = input_token->value; 1671 buf_size = input_token->length; 1672 } else if ((size_t)mech_len == GSS_KRB5_MECH->length && 1673 memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0) 1674 return (gss_init_sec_context(minor_status, 1675 initiator_cred_handle, 1676 context_handle, 1677 target_name, 1678 GSS_KRB5_MECH, 1679 req_flags, 1680 time_req, 1681 input_chan_bindings, 1682 input_token, 1683 actual_mech_type, 1684 output_token, 1685 ret_flags, 1686 time_rec)); 1687 else if ((size_t)mech_len == GSS_SPNEGO_MECH->length && 1688 memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) { 1689 ret = gssapi_spnego_decapsulate(minor_status, 1690 input_token, 1691 &buf, 1692 &buf_size, 1693 GSS_SPNEGO_MECH); 1694 if (ret) 1695 return (ret); 1696 } else 1697 return (GSS_S_BAD_MECH); 1698 1699 ret = der_match_tag_and_length(buf, buf_size, 1700 ASN1_C_CONTEXT, CONS, 1, &len, &taglen); 1701 if (ret) 1702 return (ret); 1703 1704 if(len > buf_size - taglen) 1705 return (ASN1_OVERRUN); 1706 1707 ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL); 1708 if (ret) { 1709 free_NegTokenResp(&resp); 1710 *minor_status = ENOMEM; 1711 return (GSS_S_FAILURE); 1712 } 1713 1714 if (resp.negState == NULL || 1715 *(resp.negState) == reject || 1716 resp.supportedMech == NULL) { 1717 free_NegTokenResp(&resp); 1718 return (GSS_S_BAD_MECH); 1719 } 1720 1721 ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1, 1722 sizeof(oidbuf), 1723 resp.supportedMech, 1724 &oidlen); 1725 if (ret || oidlen != GSS_KRB5_MECH->length || 1726 memcmp(oidbuf + sizeof(oidbuf) - oidlen, 1727 GSS_KRB5_MECH->elements, 1728 oidlen) != 0) { 1729 free_NegTokenResp(&resp); 1730 return GSS_S_BAD_MECH; 1731 } 1732 1733 if (resp.responseToken != NULL) { 1734 sub_token.length = resp.responseToken->length; 1735 sub_token.value = resp.responseToken->data; 1736 } else { 1737 sub_token.length = 0; 1738 sub_token.value = NULL; 1739 } 1740 1741 ret = gss_init_sec_context(minor_status, 1742 initiator_cred_handle, 1743 context_handle, 1744 target_name, 1745 GSS_KRB5_MECH, 1746 req_flags, 1747 time_req, 1748 input_chan_bindings, 1749 &sub_token, 1750 actual_mech_type, 1751 output_token, 1752 ret_flags, 1753 time_rec); 1754 if (ret) { 1755 free_NegTokenResp(&resp); 1756 return (ret); 1757 } 1758 1759 /* 1760 * XXXSRA I don't think this limited implementation ever needs 1761 * to check the MIC -- our preferred mechanism (Kerberos) 1762 * authenticates its own messages and is the only mechanism 1763 * we'll accept, so if the mechanism negotiation completes 1764 * successfully, we don't need the MIC. See RFC 4178. 1765 */ 1766 1767 free_NegTokenResp(&resp); 1768 return (ret); 1769 } 1770 1771 1772 1773 OM_uint32 1774 gss_init_sec_context_spnego(OM_uint32 *minor_status, 1775 const gss_cred_id_t initiator_cred_handle, 1776 gss_ctx_id_t *context_handle, 1777 const gss_name_t target_name, 1778 const gss_OID mech_type, 1779 OM_uint32 req_flags, 1780 OM_uint32 time_req, 1781 const gss_channel_bindings_t input_chan_bindings, 1782 const gss_buffer_t input_token, 1783 gss_OID *actual_mech_type, 1784 gss_buffer_t output_token, 1785 OM_uint32 *ret_flags, 1786 OM_uint32 *time_rec) 1787 { 1788 /* Dirty trick to suppress compiler warnings */ 1789 1790 /* Figure out whether we're starting over or processing a reply */ 1791 1792 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U) 1793 return (spnego_initial(minor_status, 1794 initiator_cred_handle, 1795 context_handle, 1796 target_name, 1797 mech_type, 1798 req_flags, 1799 time_req, 1800 input_chan_bindings, 1801 input_token, 1802 actual_mech_type, 1803 output_token, 1804 ret_flags, 1805 time_rec)); 1806 else 1807 return (spnego_reply(minor_status, 1808 initiator_cred_handle, 1809 context_handle, 1810 target_name, 1811 mech_type, 1812 req_flags, 1813 time_req, 1814 input_chan_bindings, 1815 input_token, 1816 actual_mech_type, 1817 output_token, 1818 ret_flags, 1819 time_rec)); 1820 } 1821 1822 #endif /* GSSAPI */ 1823