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