1193141Sdougb/* 2262706Serwin * Copyright (C) 2006-2014 Internet Systems Consortium, Inc. ("ISC") 3193141Sdougb * 4193141Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5193141Sdougb * purpose with or without fee is hereby granted, provided that the above 6193141Sdougb * copyright notice and this permission notice appear in all copies. 7193141Sdougb * 8193141Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9193141Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10193141Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11193141Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12193141Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13193141Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14193141Sdougb * PERFORMANCE OF THIS SOFTWARE. 15193141Sdougb */ 16193141Sdougb 17234010Sdougb/* $Id$ */ 18193141Sdougb 19193141Sdougb/*! \file 20193141Sdougb * \brief 21193141Sdougb * Portable SPNEGO implementation. 22193141Sdougb * 23193141Sdougb * This is part of a portable implementation of the SPNEGO protocol 24193141Sdougb * (RFCs 2478 and 4178). This implementation uses the RFC 4178 ASN.1 25193141Sdougb * module but is not a full implementation of the RFC 4178 protocol; 26193141Sdougb * at the moment, we only support GSS-TSIG with Kerberos 27193141Sdougb * authentication, so we only need enough of the SPNEGO protocol to 28193141Sdougb * support that. 29193141Sdougb * 30193141Sdougb * The files that make up this portable SPNEGO implementation are: 31193141Sdougb * \li spnego.c (this file) 32193141Sdougb * \li spnego.h (API SPNEGO exports to the rest of lib/dns) 33193141Sdougb * \li spnego.asn1 (SPNEGO ASN.1 module) 34193141Sdougb * \li spnego_asn1.c (routines generated from spngo.asn1) 35193141Sdougb * \li spnego_asn1.pl (perl script to generate spnego_asn1.c) 36193141Sdougb * 37193141Sdougb * Everything but the functions exported in spnego.h is static, to 38193141Sdougb * avoid possible conflicts with other libraries (particularly Heimdal, 39193141Sdougb * since much of this code comes from Heimdal by way of mod_auth_kerb). 40193141Sdougb * 41193141Sdougb * spnego_asn1.c is shipped as part of lib/dns because generating it 42193141Sdougb * requires both Perl and the Heimdal ASN.1 compiler. See 43193141Sdougb * spnego_asn1.pl for further details. We've tried to eliminate all 44193141Sdougb * compiler warnings from the generated code, but you may see a few 45193141Sdougb * when using a compiler version we haven't tested yet. 46193141Sdougb */ 47193141Sdougb 48193141Sdougb/* 49193141Sdougb * Portions of this code were derived from mod_auth_kerb and Heimdal. 50193141Sdougb * These packages are available from: 51193141Sdougb * 52193141Sdougb * http://modauthkerb.sourceforge.net/ 53193141Sdougb * http://www.pdc.kth.se/heimdal/ 54193141Sdougb * 55193141Sdougb * and were released under the following licenses: 56193141Sdougb * 57193141Sdougb * ---------------------------------------------------------------- 58193141Sdougb * 59193141Sdougb * Copyright (c) 2004 Masarykova universita 60193141Sdougb * (Masaryk University, Brno, Czech Republic) 61193141Sdougb * All rights reserved. 62193141Sdougb * 63193141Sdougb * Redistribution and use in source and binary forms, with or without 64193141Sdougb * modification, are permitted provided that the following conditions are met: 65193141Sdougb * 66193141Sdougb * 1. Redistributions of source code must retain the above copyright notice, 67193141Sdougb * this list of conditions and the following disclaimer. 68193141Sdougb * 69193141Sdougb * 2. Redistributions in binary form must reproduce the above copyright 70193141Sdougb * notice, this list of conditions and the following disclaimer in the 71193141Sdougb * documentation and/or other materials provided with the distribution. 72193141Sdougb * 73193141Sdougb * 3. Neither the name of the University nor the names of its contributors may 74193141Sdougb * be used to endorse or promote products derived from this software 75193141Sdougb * without specific prior written permission. 76193141Sdougb * 77193141Sdougb * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 78193141Sdougb * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 79193141Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 80193141Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 81193141Sdougb * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 82193141Sdougb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 83193141Sdougb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 84193141Sdougb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 85193141Sdougb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 86193141Sdougb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 87193141Sdougb * POSSIBILITY OF SUCH DAMAGE. 88193141Sdougb * 89193141Sdougb * ---------------------------------------------------------------- 90193141Sdougb * 91193141Sdougb * Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan 92193141Sdougb * (Royal Institute of Technology, Stockholm, Sweden). 93193141Sdougb * All rights reserved. 94193141Sdougb * 95193141Sdougb * Redistribution and use in source and binary forms, with or without 96193141Sdougb * modification, are permitted provided that the following conditions 97193141Sdougb * are met: 98193141Sdougb * 99193141Sdougb * 1. Redistributions of source code must retain the above copyright 100193141Sdougb * notice, this list of conditions and the following disclaimer. 101193141Sdougb * 102193141Sdougb * 2. Redistributions in binary form must reproduce the above copyright 103193141Sdougb * notice, this list of conditions and the following disclaimer in the 104193141Sdougb * documentation and/or other materials provided with the distribution. 105193141Sdougb * 106193141Sdougb * 3. Neither the name of the Institute nor the names of its contributors 107193141Sdougb * may be used to endorse or promote products derived from this software 108193141Sdougb * without specific prior written permission. 109193141Sdougb * 110193141Sdougb * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 111193141Sdougb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 112193141Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 113193141Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 114193141Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 115193141Sdougb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 116193141Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 117193141Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 118193141Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 119193141Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 120193141Sdougb * SUCH DAMAGE. 121193141Sdougb */ 122193141Sdougb 123193141Sdougb/* 124193141Sdougb * XXXSRA We should omit this file entirely in Makefile.in via autoconf, 125193141Sdougb * but this will keep it from generating errors until that's written. 126193141Sdougb */ 127193141Sdougb 128193141Sdougb#ifdef GSSAPI 129193141Sdougb 130193141Sdougb/* 131193141Sdougb * XXXSRA Some of the following files are almost certainly unnecessary, 132193141Sdougb * but using this list (borrowed from gssapictx.c) gets rid of some 133193141Sdougb * whacky compilation errors when building with MSVC and should be 134193141Sdougb * harmless in any case. 135193141Sdougb */ 136193141Sdougb 137193141Sdougb#include <config.h> 138193141Sdougb 139193141Sdougb#include <stdlib.h> 140193141Sdougb#include <errno.h> 141193141Sdougb 142193141Sdougb#include <isc/buffer.h> 143193141Sdougb#include <isc/dir.h> 144193141Sdougb#include <isc/entropy.h> 145193141Sdougb#include <isc/lex.h> 146193141Sdougb#include <isc/mem.h> 147193141Sdougb#include <isc/once.h> 148193141Sdougb#include <isc/random.h> 149193141Sdougb#include <isc/string.h> 150193141Sdougb#include <isc/time.h> 151193141Sdougb#include <isc/util.h> 152193141Sdougb 153193141Sdougb#include <dns/fixedname.h> 154193141Sdougb#include <dns/name.h> 155193141Sdougb#include <dns/rdata.h> 156193141Sdougb#include <dns/rdataclass.h> 157193141Sdougb#include <dns/result.h> 158193141Sdougb#include <dns/types.h> 159193141Sdougb#include <dns/keyvalues.h> 160193141Sdougb#include <dns/log.h> 161193141Sdougb 162193141Sdougb#include <dst/gssapi.h> 163193141Sdougb#include <dst/result.h> 164193141Sdougb 165193141Sdougb#include "dst_internal.h" 166193141Sdougb 167193141Sdougb/* 168193141Sdougb * The API we export 169193141Sdougb */ 170193141Sdougb#include "spnego.h" 171193141Sdougb 172193141Sdougb/* asn1_err.h */ 173193141Sdougb/* Generated from ../../../lib/asn1/asn1_err.et */ 174193141Sdougb 175224092Sdougb#ifndef ERROR_TABLE_BASE_asn1 176224092Sdougb/* these may be brought in already via gssapi_krb5.h */ 177193141Sdougbtypedef enum asn1_error_number { 178193141Sdougb ASN1_BAD_TIMEFORMAT = 1859794432, 179193141Sdougb ASN1_MISSING_FIELD = 1859794433, 180193141Sdougb ASN1_MISPLACED_FIELD = 1859794434, 181193141Sdougb ASN1_TYPE_MISMATCH = 1859794435, 182193141Sdougb ASN1_OVERFLOW = 1859794436, 183193141Sdougb ASN1_OVERRUN = 1859794437, 184193141Sdougb ASN1_BAD_ID = 1859794438, 185193141Sdougb ASN1_BAD_LENGTH = 1859794439, 186193141Sdougb ASN1_BAD_FORMAT = 1859794440, 187193141Sdougb ASN1_PARSE_ERROR = 1859794441 188193141Sdougb} asn1_error_number; 189193141Sdougb 190193141Sdougb#define ERROR_TABLE_BASE_asn1 1859794432 191224092Sdougb#endif 192193141Sdougb 193193141Sdougb#define __asn1_common_definitions__ 194193141Sdougb 195193141Sdougbtypedef struct octet_string { 196193141Sdougb size_t length; 197193141Sdougb void *data; 198193141Sdougb} octet_string; 199193141Sdougb 200193141Sdougbtypedef char *general_string; 201193141Sdougb 202193141Sdougbtypedef char *utf8_string; 203193141Sdougb 204193141Sdougbtypedef struct oid { 205193141Sdougb size_t length; 206193141Sdougb unsigned *components; 207193141Sdougb} oid; 208193141Sdougb 209193141Sdougb/* der.h */ 210193141Sdougb 211193141Sdougbtypedef enum { 212193141Sdougb ASN1_C_UNIV = 0, ASN1_C_APPL = 1, 213193141Sdougb ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3 214193141Sdougb} Der_class; 215193141Sdougb 216193141Sdougbtypedef enum { 217193141Sdougb PRIM = 0, CONS = 1 218193141Sdougb} Der_type; 219193141Sdougb 220193141Sdougb/* Universal tags */ 221193141Sdougb 222193141Sdougbenum { 223193141Sdougb UT_Boolean = 1, 224193141Sdougb UT_Integer = 2, 225193141Sdougb UT_BitString = 3, 226193141Sdougb UT_OctetString = 4, 227193141Sdougb UT_Null = 5, 228193141Sdougb UT_OID = 6, 229193141Sdougb UT_Enumerated = 10, 230193141Sdougb UT_Sequence = 16, 231193141Sdougb UT_Set = 17, 232193141Sdougb UT_PrintableString = 19, 233193141Sdougb UT_IA5String = 22, 234193141Sdougb UT_UTCTime = 23, 235193141Sdougb UT_GeneralizedTime = 24, 236193141Sdougb UT_VisibleString = 26, 237193141Sdougb UT_GeneralString = 27 238193141Sdougb}; 239193141Sdougb 240193141Sdougb#define ASN1_INDEFINITE 0xdce0deed 241193141Sdougb 242193141Sdougbstatic int 243193141Sdougbder_get_length(const unsigned char *p, size_t len, 244193141Sdougb size_t * val, size_t * size); 245193141Sdougb 246193141Sdougbstatic int 247193141Sdougbder_get_octet_string(const unsigned char *p, size_t len, 248193141Sdougb octet_string * data, size_t * size); 249193141Sdougbstatic int 250193141Sdougbder_get_oid(const unsigned char *p, size_t len, 251193141Sdougb oid * data, size_t * size); 252193141Sdougbstatic int 253193141Sdougbder_get_tag(const unsigned char *p, size_t len, 254193141Sdougb Der_class * class, Der_type * type, 255193141Sdougb int *tag, size_t * size); 256193141Sdougb 257193141Sdougbstatic int 258193141Sdougbder_match_tag(const unsigned char *p, size_t len, 259193141Sdougb Der_class class, Der_type type, 260193141Sdougb int tag, size_t * size); 261193141Sdougbstatic int 262193141Sdougbder_match_tag_and_length(const unsigned char *p, size_t len, 263193141Sdougb Der_class class, Der_type type, int tag, 264193141Sdougb size_t * length_ret, size_t * size); 265193141Sdougb 266193141Sdougbstatic int 267193141Sdougbdecode_oid(const unsigned char *p, size_t len, 268193141Sdougb oid * k, size_t * size); 269193141Sdougb 270193141Sdougbstatic int 271204619Sdougbdecode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size); 272193141Sdougb 273193141Sdougbstatic int 274193141Sdougbdecode_octet_string(const unsigned char *, size_t, octet_string *, size_t *); 275193141Sdougb 276193141Sdougbstatic int 277193141Sdougbder_put_int(unsigned char *p, size_t len, int val, size_t *); 278193141Sdougb 279193141Sdougbstatic int 280193141Sdougbder_put_length(unsigned char *p, size_t len, size_t val, size_t *); 281193141Sdougb 282193141Sdougbstatic int 283193141Sdougbder_put_octet_string(unsigned char *p, size_t len, 284193141Sdougb const octet_string * data, size_t *); 285193141Sdougbstatic int 286193141Sdougbder_put_oid(unsigned char *p, size_t len, 287193141Sdougb const oid * data, size_t * size); 288193141Sdougbstatic int 289193141Sdougbder_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, 290193141Sdougb int tag, size_t *); 291193141Sdougbstatic int 292193141Sdougbder_put_length_and_tag(unsigned char *, size_t, size_t, 293193141Sdougb Der_class, Der_type, int, size_t *); 294193141Sdougb 295193141Sdougbstatic int 296204619Sdougbencode_enumerated(unsigned char *p, size_t len, const void *data, size_t *); 297193141Sdougb 298193141Sdougbstatic int 299193141Sdougbencode_octet_string(unsigned char *p, size_t len, 300193141Sdougb const octet_string * k, size_t *); 301193141Sdougbstatic int 302193141Sdougbencode_oid(unsigned char *p, size_t len, 303193141Sdougb const oid * k, size_t *); 304193141Sdougb 305193141Sdougbstatic void 306193141Sdougbfree_octet_string(octet_string * k); 307193141Sdougb 308193141Sdougbstatic void 309193141Sdougbfree_oid (oid * k); 310193141Sdougb 311193141Sdougbstatic size_t 312193141Sdougblength_len(size_t len); 313193141Sdougb 314193141Sdougbstatic int 315193141Sdougbfix_dce(size_t reallen, size_t * len); 316193141Sdougb 317193141Sdougb/* 318193141Sdougb * Include stuff generated by the ASN.1 compiler. 319193141Sdougb */ 320193141Sdougb 321193141Sdougb#include "spnego_asn1.c" 322193141Sdougb 323193141Sdougbstatic unsigned char gss_krb5_mech_oid_bytes[] = { 324193141Sdougb 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 325193141Sdougb}; 326193141Sdougb 327193141Sdougbstatic gss_OID_desc gss_krb5_mech_oid_desc = { 328193141Sdougb sizeof(gss_krb5_mech_oid_bytes), 329193141Sdougb gss_krb5_mech_oid_bytes 330193141Sdougb}; 331193141Sdougb 332193141Sdougbstatic gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc; 333193141Sdougb 334193141Sdougbstatic unsigned char gss_mskrb5_mech_oid_bytes[] = { 335193141Sdougb 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02 336193141Sdougb}; 337193141Sdougb 338193141Sdougbstatic gss_OID_desc gss_mskrb5_mech_oid_desc = { 339193141Sdougb sizeof(gss_mskrb5_mech_oid_bytes), 340193141Sdougb gss_mskrb5_mech_oid_bytes 341193141Sdougb}; 342193141Sdougb 343193141Sdougbstatic gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc; 344193141Sdougb 345193141Sdougbstatic unsigned char gss_spnego_mech_oid_bytes[] = { 346193141Sdougb 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 347193141Sdougb}; 348193141Sdougb 349193141Sdougbstatic gss_OID_desc gss_spnego_mech_oid_desc = { 350193141Sdougb sizeof(gss_spnego_mech_oid_bytes), 351193141Sdougb gss_spnego_mech_oid_bytes 352193141Sdougb}; 353193141Sdougb 354193141Sdougbstatic gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc; 355193141Sdougb 356193141Sdougb/* spnegokrb5_locl.h */ 357193141Sdougb 358193141Sdougbstatic OM_uint32 359193141Sdougbgssapi_spnego_encapsulate(OM_uint32 *, 360193141Sdougb unsigned char *, 361193141Sdougb size_t, 362193141Sdougb gss_buffer_t, 363193141Sdougb const gss_OID); 364193141Sdougb 365193141Sdougbstatic OM_uint32 366193141Sdougbgssapi_spnego_decapsulate(OM_uint32 *, 367193141Sdougb gss_buffer_t, 368193141Sdougb unsigned char **, 369193141Sdougb size_t *, 370193141Sdougb const gss_OID); 371193141Sdougb 372193141Sdougb/* mod_auth_kerb.c */ 373193141Sdougb 374193141Sdougbstatic int 375193141Sdougbcmp_gss_type(gss_buffer_t token, gss_OID oid) 376193141Sdougb{ 377193141Sdougb unsigned char *p; 378193141Sdougb size_t len; 379193141Sdougb 380225361Sdougb if (token->length == 0U) 381193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 382193141Sdougb 383193141Sdougb p = token->value; 384193141Sdougb if (*p++ != 0x60) 385193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 386193141Sdougb len = *p++; 387193141Sdougb if (len & 0x80) { 388225361Sdougb if ((len & 0x7f) > 4U) 389193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 390193141Sdougb p += len & 0x7f; 391193141Sdougb } 392193141Sdougb if (*p++ != 0x06) 393193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 394193141Sdougb 395193141Sdougb if (((OM_uint32) *p++) != oid->length) 396193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 397193141Sdougb 398193141Sdougb return (memcmp(p, oid->elements, oid->length)); 399193141Sdougb} 400193141Sdougb 401193141Sdougb/* accept_sec_context.c */ 402193141Sdougb/* 403193141Sdougb * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly 404193141Sdougb * based on Heimdal code) 405193141Sdougb */ 406193141Sdougb 407193141Sdougbstatic OM_uint32 408193141Sdougbcode_NegTokenArg(OM_uint32 * minor_status, 409193141Sdougb const NegTokenResp * resp, 410193141Sdougb unsigned char **outbuf, 411193141Sdougb size_t * outbuf_size) 412193141Sdougb{ 413193141Sdougb OM_uint32 ret; 414193141Sdougb u_char *buf; 415224092Sdougb size_t buf_size, buf_len = 0; 416193141Sdougb 417193141Sdougb buf_size = 1024; 418193141Sdougb buf = malloc(buf_size); 419193141Sdougb if (buf == NULL) { 420193141Sdougb *minor_status = ENOMEM; 421193141Sdougb return (GSS_S_FAILURE); 422193141Sdougb } 423193141Sdougb do { 424193141Sdougb ret = encode_NegTokenResp(buf + buf_size - 1, 425193141Sdougb buf_size, 426193141Sdougb resp, &buf_len); 427193141Sdougb if (ret == 0) { 428193141Sdougb size_t tmp; 429193141Sdougb 430193141Sdougb ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, 431193141Sdougb buf_size - buf_len, 432193141Sdougb buf_len, 433193141Sdougb ASN1_C_CONTEXT, 434193141Sdougb CONS, 435193141Sdougb 1, 436193141Sdougb &tmp); 437193141Sdougb if (ret == 0) 438193141Sdougb buf_len += tmp; 439193141Sdougb } 440193141Sdougb if (ret) { 441193141Sdougb if (ret == ASN1_OVERFLOW) { 442193141Sdougb u_char *tmp; 443193141Sdougb 444193141Sdougb buf_size *= 2; 445193141Sdougb tmp = realloc(buf, buf_size); 446193141Sdougb if (tmp == NULL) { 447193141Sdougb *minor_status = ENOMEM; 448193141Sdougb free(buf); 449193141Sdougb return (GSS_S_FAILURE); 450193141Sdougb } 451193141Sdougb buf = tmp; 452193141Sdougb } else { 453193141Sdougb *minor_status = ret; 454193141Sdougb free(buf); 455193141Sdougb return (GSS_S_FAILURE); 456193141Sdougb } 457193141Sdougb } 458193141Sdougb } while (ret == ASN1_OVERFLOW); 459193141Sdougb 460193141Sdougb *outbuf = malloc(buf_len); 461193141Sdougb if (*outbuf == NULL) { 462193141Sdougb *minor_status = ENOMEM; 463193141Sdougb free(buf); 464193141Sdougb return (GSS_S_FAILURE); 465193141Sdougb } 466262706Serwin memmove(*outbuf, buf + buf_size - buf_len, buf_len); 467193141Sdougb *outbuf_size = buf_len; 468193141Sdougb 469193141Sdougb free(buf); 470193141Sdougb 471193141Sdougb return (GSS_S_COMPLETE); 472193141Sdougb} 473193141Sdougb 474193141Sdougbstatic OM_uint32 475193141Sdougbsend_reject(OM_uint32 * minor_status, 476193141Sdougb gss_buffer_t output_token) 477193141Sdougb{ 478193141Sdougb NegTokenResp resp; 479193141Sdougb OM_uint32 ret; 480193141Sdougb 481193141Sdougb resp.negState = malloc(sizeof(*resp.negState)); 482193141Sdougb if (resp.negState == NULL) { 483193141Sdougb *minor_status = ENOMEM; 484193141Sdougb return (GSS_S_FAILURE); 485193141Sdougb } 486193141Sdougb *(resp.negState) = reject; 487193141Sdougb 488193141Sdougb resp.supportedMech = NULL; 489193141Sdougb resp.responseToken = NULL; 490193141Sdougb resp.mechListMIC = NULL; 491193141Sdougb 492193141Sdougb ret = code_NegTokenArg(minor_status, &resp, 493193141Sdougb (unsigned char **)&output_token->value, 494193141Sdougb &output_token->length); 495193141Sdougb free_NegTokenResp(&resp); 496193141Sdougb if (ret) 497193141Sdougb return (ret); 498193141Sdougb 499193141Sdougb return (GSS_S_BAD_MECH); 500193141Sdougb} 501193141Sdougb 502193141Sdougbstatic OM_uint32 503193141Sdougbsend_accept(OM_uint32 * minor_status, 504193141Sdougb gss_buffer_t output_token, 505193141Sdougb gss_buffer_t mech_token, 506193141Sdougb const gss_OID pref) 507193141Sdougb{ 508193141Sdougb NegTokenResp resp; 509193141Sdougb OM_uint32 ret; 510193141Sdougb 511193141Sdougb memset(&resp, 0, sizeof(resp)); 512193141Sdougb resp.negState = malloc(sizeof(*resp.negState)); 513193141Sdougb if (resp.negState == NULL) { 514193141Sdougb *minor_status = ENOMEM; 515193141Sdougb return (GSS_S_FAILURE); 516193141Sdougb } 517193141Sdougb *(resp.negState) = accept_completed; 518193141Sdougb 519193141Sdougb resp.supportedMech = malloc(sizeof(*resp.supportedMech)); 520193141Sdougb if (resp.supportedMech == NULL) { 521193141Sdougb free_NegTokenResp(&resp); 522193141Sdougb *minor_status = ENOMEM; 523193141Sdougb return (GSS_S_FAILURE); 524193141Sdougb } 525193141Sdougb ret = der_get_oid(pref->elements, 526193141Sdougb pref->length, 527193141Sdougb resp.supportedMech, 528193141Sdougb NULL); 529193141Sdougb if (ret) { 530193141Sdougb free_NegTokenResp(&resp); 531193141Sdougb *minor_status = ENOMEM; 532193141Sdougb return (GSS_S_FAILURE); 533193141Sdougb } 534225361Sdougb if (mech_token != NULL && mech_token->length != 0U) { 535193141Sdougb resp.responseToken = malloc(sizeof(*resp.responseToken)); 536193141Sdougb if (resp.responseToken == NULL) { 537193141Sdougb free_NegTokenResp(&resp); 538193141Sdougb *minor_status = ENOMEM; 539193141Sdougb return (GSS_S_FAILURE); 540193141Sdougb } 541193141Sdougb resp.responseToken->length = mech_token->length; 542193141Sdougb resp.responseToken->data = mech_token->value; 543193141Sdougb } 544193141Sdougb 545193141Sdougb ret = code_NegTokenArg(minor_status, &resp, 546193141Sdougb (unsigned char **)&output_token->value, 547193141Sdougb &output_token->length); 548193141Sdougb if (resp.responseToken != NULL) { 549193141Sdougb free(resp.responseToken); 550193141Sdougb resp.responseToken = NULL; 551193141Sdougb } 552193141Sdougb free_NegTokenResp(&resp); 553193141Sdougb if (ret) 554193141Sdougb return (ret); 555193141Sdougb 556193141Sdougb return (GSS_S_COMPLETE); 557193141Sdougb} 558193141Sdougb 559193141SdougbOM_uint32 560193141Sdougbgss_accept_sec_context_spnego(OM_uint32 *minor_status, 561193141Sdougb gss_ctx_id_t *context_handle, 562193141Sdougb const gss_cred_id_t acceptor_cred_handle, 563193141Sdougb const gss_buffer_t input_token_buffer, 564193141Sdougb const gss_channel_bindings_t input_chan_bindings, 565193141Sdougb gss_name_t *src_name, 566193141Sdougb gss_OID *mech_type, 567193141Sdougb gss_buffer_t output_token, 568193141Sdougb OM_uint32 *ret_flags, 569193141Sdougb OM_uint32 *time_rec, 570193141Sdougb gss_cred_id_t *delegated_cred_handle) 571193141Sdougb{ 572193141Sdougb NegTokenInit init_token; 573193141Sdougb OM_uint32 major_status; 574193141Sdougb OM_uint32 minor_status2; 575193141Sdougb gss_buffer_desc ibuf, obuf; 576193141Sdougb gss_buffer_t ot = NULL; 577193141Sdougb gss_OID pref = GSS_KRB5_MECH; 578193141Sdougb unsigned char *buf; 579193141Sdougb size_t buf_size; 580193141Sdougb size_t len, taglen, ni_len; 581193141Sdougb int found = 0; 582193141Sdougb int ret; 583193141Sdougb unsigned i; 584193141Sdougb 585193141Sdougb /* 586193141Sdougb * Before doing anything else, see whether this is a SPNEGO 587193141Sdougb * PDU. If not, dispatch to the GSSAPI library and get out. 588193141Sdougb */ 589193141Sdougb 590193141Sdougb if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH)) 591193141Sdougb return (gss_accept_sec_context(minor_status, 592193141Sdougb context_handle, 593193141Sdougb acceptor_cred_handle, 594193141Sdougb input_token_buffer, 595193141Sdougb input_chan_bindings, 596193141Sdougb src_name, 597193141Sdougb mech_type, 598193141Sdougb output_token, 599193141Sdougb ret_flags, 600193141Sdougb time_rec, 601193141Sdougb delegated_cred_handle)); 602193141Sdougb 603193141Sdougb /* 604193141Sdougb * If we get here, it's SPNEGO. 605193141Sdougb */ 606193141Sdougb 607193141Sdougb memset(&init_token, 0, sizeof(init_token)); 608193141Sdougb 609193141Sdougb ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer, 610193141Sdougb &buf, &buf_size, GSS_SPNEGO_MECH); 611193141Sdougb if (ret) 612193141Sdougb return (ret); 613193141Sdougb 614193141Sdougb ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS, 615193141Sdougb 0, &len, &taglen); 616193141Sdougb if (ret) 617193141Sdougb return (ret); 618193141Sdougb 619193141Sdougb ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len); 620193141Sdougb if (ret) { 621193141Sdougb *minor_status = EINVAL; /* XXX */ 622193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 623193141Sdougb } 624193141Sdougb 625193141Sdougb for (i = 0; !found && i < init_token.mechTypes.len; ++i) { 626204619Sdougb unsigned char mechbuf[17]; 627193141Sdougb size_t mech_len; 628193141Sdougb 629193141Sdougb ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1, 630193141Sdougb sizeof(mechbuf), 631193141Sdougb &init_token.mechTypes.val[i], 632193141Sdougb &mech_len); 633254402Serwin if (ret) { 634254402Serwin free_NegTokenInit(&init_token); 635193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 636254402Serwin } 637193141Sdougb if (mech_len == GSS_KRB5_MECH->length && 638193141Sdougb memcmp(GSS_KRB5_MECH->elements, 639193141Sdougb mechbuf + sizeof(mechbuf) - mech_len, 640193141Sdougb mech_len) == 0) { 641193141Sdougb found = 1; 642193141Sdougb break; 643193141Sdougb } 644193141Sdougb if (mech_len == GSS_MSKRB5_MECH->length && 645193141Sdougb memcmp(GSS_MSKRB5_MECH->elements, 646193141Sdougb mechbuf + sizeof(mechbuf) - mech_len, 647193141Sdougb mech_len) == 0) { 648193141Sdougb found = 1; 649193141Sdougb if (i == 0) 650193141Sdougb pref = GSS_MSKRB5_MECH; 651193141Sdougb break; 652193141Sdougb } 653193141Sdougb } 654193141Sdougb 655254402Serwin if (!found) { 656254402Serwin free_NegTokenInit(&init_token); 657193141Sdougb return (send_reject(minor_status, output_token)); 658254402Serwin } 659193141Sdougb 660193141Sdougb if (i == 0 && init_token.mechToken != NULL) { 661193141Sdougb ibuf.length = init_token.mechToken->length; 662193141Sdougb ibuf.value = init_token.mechToken->data; 663193141Sdougb 664193141Sdougb major_status = gss_accept_sec_context(minor_status, 665193141Sdougb context_handle, 666193141Sdougb acceptor_cred_handle, 667193141Sdougb &ibuf, 668193141Sdougb input_chan_bindings, 669193141Sdougb src_name, 670193141Sdougb mech_type, 671193141Sdougb &obuf, 672193141Sdougb ret_flags, 673193141Sdougb time_rec, 674193141Sdougb delegated_cred_handle); 675193141Sdougb if (GSS_ERROR(major_status)) { 676254402Serwin free_NegTokenInit(&init_token); 677193141Sdougb send_reject(&minor_status2, output_token); 678193141Sdougb return (major_status); 679193141Sdougb } 680193141Sdougb ot = &obuf; 681193141Sdougb } 682193141Sdougb ret = send_accept(&minor_status2, output_token, ot, pref); 683254402Serwin free_NegTokenInit(&init_token); 684225361Sdougb if (ot != NULL && ot->length != 0U) 685193141Sdougb gss_release_buffer(&minor_status2, ot); 686193141Sdougb 687193141Sdougb return (ret); 688193141Sdougb} 689193141Sdougb 690193141Sdougb/* decapsulate.c */ 691193141Sdougb 692193141Sdougbstatic OM_uint32 693193141Sdougbgssapi_verify_mech_header(u_char ** str, 694193141Sdougb size_t total_len, 695193141Sdougb const gss_OID mech) 696193141Sdougb{ 697193141Sdougb size_t len, len_len, mech_len, foo; 698193141Sdougb int e; 699193141Sdougb u_char *p = *str; 700193141Sdougb 701225361Sdougb if (total_len < 1U) 702193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 703193141Sdougb if (*p++ != 0x60) 704193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 705193141Sdougb e = der_get_length(p, total_len - 1, &len, &len_len); 706193141Sdougb if (e || 1 + len_len + len != total_len) 707193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 708193141Sdougb p += len_len; 709193141Sdougb if (*p++ != 0x06) 710193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 711193141Sdougb e = der_get_length(p, total_len - 1 - len_len - 1, 712193141Sdougb &mech_len, &foo); 713193141Sdougb if (e) 714193141Sdougb return (GSS_S_DEFECTIVE_TOKEN); 715193141Sdougb p += foo; 716193141Sdougb if (mech_len != mech->length) 717193141Sdougb return (GSS_S_BAD_MECH); 718193141Sdougb if (memcmp(p, mech->elements, mech->length) != 0) 719193141Sdougb return (GSS_S_BAD_MECH); 720193141Sdougb p += mech_len; 721193141Sdougb *str = p; 722193141Sdougb return (GSS_S_COMPLETE); 723193141Sdougb} 724193141Sdougb 725193141Sdougb/* 726193141Sdougb * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does 727193141Sdougb * not copy data, so just free `in_token'. 728193141Sdougb */ 729193141Sdougb 730193141Sdougbstatic OM_uint32 731193141Sdougbgssapi_spnego_decapsulate(OM_uint32 *minor_status, 732193141Sdougb gss_buffer_t input_token_buffer, 733193141Sdougb unsigned char **buf, 734193141Sdougb size_t *buf_len, 735193141Sdougb const gss_OID mech) 736193141Sdougb{ 737193141Sdougb u_char *p; 738193141Sdougb OM_uint32 ret; 739193141Sdougb 740193141Sdougb p = input_token_buffer->value; 741193141Sdougb ret = gssapi_verify_mech_header(&p, 742193141Sdougb input_token_buffer->length, 743193141Sdougb mech); 744193141Sdougb if (ret) { 745193141Sdougb *minor_status = ret; 746193141Sdougb return (GSS_S_FAILURE); 747193141Sdougb } 748193141Sdougb *buf_len = input_token_buffer->length - 749193141Sdougb (p - (u_char *) input_token_buffer->value); 750193141Sdougb *buf = p; 751193141Sdougb return (GSS_S_COMPLETE); 752193141Sdougb} 753193141Sdougb 754193141Sdougb/* der_free.c */ 755193141Sdougb 756193141Sdougbstatic void 757193141Sdougbfree_octet_string(octet_string *k) 758193141Sdougb{ 759193141Sdougb free(k->data); 760193141Sdougb k->data = NULL; 761193141Sdougb} 762193141Sdougb 763193141Sdougbstatic void 764193141Sdougbfree_oid(oid *k) 765193141Sdougb{ 766193141Sdougb free(k->components); 767193141Sdougb k->components = NULL; 768193141Sdougb} 769193141Sdougb 770193141Sdougb/* der_get.c */ 771193141Sdougb 772193141Sdougb/* 773193141Sdougb * All decoding functions take a pointer `p' to first position in which to 774193141Sdougb * read, from the left, `len' which means the maximum number of characters we 775193141Sdougb * are able to read, `ret' were the value will be returned and `size' where 776193141Sdougb * the number of used bytes is stored. Either 0 or an error code is returned. 777193141Sdougb */ 778193141Sdougb 779193141Sdougbstatic int 780193141Sdougbder_get_unsigned(const unsigned char *p, size_t len, 781193141Sdougb unsigned *ret, size_t *size) 782193141Sdougb{ 783193141Sdougb unsigned val = 0; 784193141Sdougb size_t oldlen = len; 785193141Sdougb 786193141Sdougb while (len--) 787193141Sdougb val = val * 256 + *p++; 788193141Sdougb *ret = val; 789193141Sdougb if (size) 790193141Sdougb *size = oldlen; 791193141Sdougb return (0); 792193141Sdougb} 793193141Sdougb 794193141Sdougbstatic int 795193141Sdougbder_get_int(const unsigned char *p, size_t len, 796193141Sdougb int *ret, size_t *size) 797193141Sdougb{ 798193141Sdougb int val = 0; 799193141Sdougb size_t oldlen = len; 800193141Sdougb 801225361Sdougb if (len > 0U) { 802193141Sdougb val = (signed char)*p++; 803193141Sdougb while (--len) 804193141Sdougb val = val * 256 + *p++; 805193141Sdougb } 806193141Sdougb *ret = val; 807193141Sdougb if (size) 808193141Sdougb *size = oldlen; 809193141Sdougb return (0); 810193141Sdougb} 811193141Sdougb 812193141Sdougbstatic int 813193141Sdougbder_get_length(const unsigned char *p, size_t len, 814193141Sdougb size_t *val, size_t *size) 815193141Sdougb{ 816193141Sdougb size_t v; 817193141Sdougb 818225361Sdougb if (len <= 0U) 819193141Sdougb return (ASN1_OVERRUN); 820193141Sdougb --len; 821193141Sdougb v = *p++; 822225361Sdougb if (v < 128U) { 823193141Sdougb *val = v; 824193141Sdougb if (size) 825193141Sdougb *size = 1; 826193141Sdougb } else { 827193141Sdougb int e; 828193141Sdougb size_t l; 829193141Sdougb unsigned tmp; 830193141Sdougb 831225361Sdougb if (v == 0x80U) { 832193141Sdougb *val = ASN1_INDEFINITE; 833193141Sdougb if (size) 834193141Sdougb *size = 1; 835193141Sdougb return (0); 836193141Sdougb } 837193141Sdougb v &= 0x7F; 838193141Sdougb if (len < v) 839193141Sdougb return (ASN1_OVERRUN); 840193141Sdougb e = der_get_unsigned(p, v, &tmp, &l); 841193141Sdougb if (e) 842193141Sdougb return (e); 843193141Sdougb *val = tmp; 844193141Sdougb if (size) 845193141Sdougb *size = l + 1; 846193141Sdougb } 847193141Sdougb return (0); 848193141Sdougb} 849193141Sdougb 850193141Sdougbstatic int 851193141Sdougbder_get_octet_string(const unsigned char *p, size_t len, 852193141Sdougb octet_string *data, size_t *size) 853193141Sdougb{ 854193141Sdougb data->length = len; 855254402Serwin if (len != 0U) { 856254402Serwin data->data = malloc(len); 857254402Serwin if (data->data == NULL) 858254402Serwin return (ENOMEM); 859262706Serwin memmove(data->data, p, len); 860254402Serwin } else 861254402Serwin data->data = NULL; 862193141Sdougb if (size) 863193141Sdougb *size = len; 864193141Sdougb return (0); 865193141Sdougb} 866193141Sdougb 867193141Sdougbstatic int 868193141Sdougbder_get_oid(const unsigned char *p, size_t len, 869193141Sdougb oid *data, size_t *size) 870193141Sdougb{ 871193141Sdougb int n; 872193141Sdougb size_t oldlen = len; 873193141Sdougb 874254402Serwin data->components = NULL; 875254402Serwin data->length = 0; 876225361Sdougb if (len < 1U) 877193141Sdougb return (ASN1_OVERRUN); 878193141Sdougb 879193141Sdougb data->components = malloc(len * sizeof(*data->components)); 880225361Sdougb if (data->components == NULL && len != 0U) 881193141Sdougb return (ENOMEM); 882193141Sdougb data->components[0] = (*p) / 40; 883193141Sdougb data->components[1] = (*p) % 40; 884193141Sdougb --len; 885193141Sdougb ++p; 886225361Sdougb for (n = 2; len > 0U; ++n) { 887193141Sdougb unsigned u = 0; 888193141Sdougb 889193141Sdougb do { 890193141Sdougb --len; 891193141Sdougb u = u * 128 + (*p++ % 128); 892225361Sdougb } while (len > 0U && p[-1] & 0x80); 893193141Sdougb data->components[n] = u; 894193141Sdougb } 895193141Sdougb if (p[-1] & 0x80) { 896193141Sdougb free_oid(data); 897193141Sdougb return (ASN1_OVERRUN); 898193141Sdougb } 899193141Sdougb data->length = n; 900193141Sdougb if (size) 901193141Sdougb *size = oldlen; 902193141Sdougb return (0); 903193141Sdougb} 904193141Sdougb 905193141Sdougbstatic int 906193141Sdougbder_get_tag(const unsigned char *p, size_t len, 907193141Sdougb Der_class *class, Der_type *type, 908193141Sdougb int *tag, size_t *size) 909193141Sdougb{ 910225361Sdougb if (len < 1U) 911193141Sdougb return (ASN1_OVERRUN); 912193141Sdougb *class = (Der_class) (((*p) >> 6) & 0x03); 913193141Sdougb *type = (Der_type) (((*p) >> 5) & 0x01); 914193141Sdougb *tag = (*p) & 0x1F; 915193141Sdougb if (size) 916193141Sdougb *size = 1; 917193141Sdougb return (0); 918193141Sdougb} 919193141Sdougb 920193141Sdougbstatic int 921193141Sdougbder_match_tag(const unsigned char *p, size_t len, 922193141Sdougb Der_class class, Der_type type, 923193141Sdougb int tag, size_t *size) 924193141Sdougb{ 925193141Sdougb size_t l; 926193141Sdougb Der_class thisclass; 927193141Sdougb Der_type thistype; 928193141Sdougb int thistag; 929193141Sdougb int e; 930193141Sdougb 931193141Sdougb e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l); 932193141Sdougb if (e) 933193141Sdougb return (e); 934193141Sdougb if (class != thisclass || type != thistype) 935193141Sdougb return (ASN1_BAD_ID); 936193141Sdougb if (tag > thistag) 937193141Sdougb return (ASN1_MISPLACED_FIELD); 938193141Sdougb if (tag < thistag) 939193141Sdougb return (ASN1_MISSING_FIELD); 940193141Sdougb if (size) 941193141Sdougb *size = l; 942193141Sdougb return (0); 943193141Sdougb} 944193141Sdougb 945193141Sdougbstatic int 946193141Sdougbder_match_tag_and_length(const unsigned char *p, size_t len, 947193141Sdougb Der_class class, Der_type type, int tag, 948193141Sdougb size_t *length_ret, size_t *size) 949193141Sdougb{ 950193141Sdougb size_t l, ret = 0; 951193141Sdougb int e; 952193141Sdougb 953193141Sdougb e = der_match_tag(p, len, class, type, tag, &l); 954193141Sdougb if (e) 955193141Sdougb return (e); 956193141Sdougb p += l; 957193141Sdougb len -= l; 958193141Sdougb ret += l; 959193141Sdougb e = der_get_length(p, len, length_ret, &l); 960193141Sdougb if (e) 961193141Sdougb return (e); 962234010Sdougb /* p += l; */ 963193141Sdougb len -= l; 964234010Sdougb POST(len); 965193141Sdougb ret += l; 966193141Sdougb if (size) 967193141Sdougb *size = ret; 968193141Sdougb return (0); 969193141Sdougb} 970193141Sdougb 971193141Sdougbstatic int 972204619Sdougbdecode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size) 973193141Sdougb{ 974193141Sdougb size_t ret = 0; 975193141Sdougb size_t l, reallen; 976193141Sdougb int e; 977193141Sdougb 978193141Sdougb e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); 979193141Sdougb if (e) 980193141Sdougb return (e); 981193141Sdougb p += l; 982193141Sdougb len -= l; 983193141Sdougb ret += l; 984193141Sdougb e = der_get_length(p, len, &reallen, &l); 985193141Sdougb if (e) 986193141Sdougb return (e); 987193141Sdougb p += l; 988193141Sdougb len -= l; 989193141Sdougb ret += l; 990193141Sdougb e = der_get_int(p, reallen, num, &l); 991193141Sdougb if (e) 992193141Sdougb return (e); 993193141Sdougb p += l; 994193141Sdougb len -= l; 995234010Sdougb POST(p); POST(len); 996193141Sdougb ret += l; 997193141Sdougb if (size) 998193141Sdougb *size = ret; 999193141Sdougb return (0); 1000193141Sdougb} 1001193141Sdougb 1002193141Sdougbstatic int 1003193141Sdougbdecode_octet_string(const unsigned char *p, size_t len, 1004193141Sdougb octet_string *k, size_t *size) 1005193141Sdougb{ 1006193141Sdougb size_t ret = 0; 1007193141Sdougb size_t l; 1008193141Sdougb int e; 1009193141Sdougb size_t slen; 1010193141Sdougb 1011254402Serwin k->data = NULL; 1012254402Serwin k->length = 0; 1013254402Serwin 1014193141Sdougb e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l); 1015193141Sdougb if (e) 1016193141Sdougb return (e); 1017193141Sdougb p += l; 1018193141Sdougb len -= l; 1019193141Sdougb ret += l; 1020193141Sdougb 1021193141Sdougb e = der_get_length(p, len, &slen, &l); 1022193141Sdougb if (e) 1023193141Sdougb return (e); 1024193141Sdougb p += l; 1025193141Sdougb len -= l; 1026193141Sdougb ret += l; 1027193141Sdougb if (len < slen) 1028193141Sdougb return (ASN1_OVERRUN); 1029193141Sdougb 1030193141Sdougb e = der_get_octet_string(p, slen, k, &l); 1031193141Sdougb if (e) 1032193141Sdougb return (e); 1033193141Sdougb p += l; 1034193141Sdougb len -= l; 1035234010Sdougb POST(p); POST(len); 1036193141Sdougb ret += l; 1037193141Sdougb if (size) 1038193141Sdougb *size = ret; 1039193141Sdougb return (0); 1040193141Sdougb} 1041193141Sdougb 1042193141Sdougbstatic int 1043193141Sdougbdecode_oid(const unsigned char *p, size_t len, 1044193141Sdougb oid *k, size_t *size) 1045193141Sdougb{ 1046193141Sdougb size_t ret = 0; 1047193141Sdougb size_t l; 1048193141Sdougb int e; 1049193141Sdougb size_t slen; 1050193141Sdougb 1051193141Sdougb e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l); 1052193141Sdougb if (e) 1053193141Sdougb return (e); 1054193141Sdougb p += l; 1055193141Sdougb len -= l; 1056193141Sdougb ret += l; 1057193141Sdougb 1058193141Sdougb e = der_get_length(p, len, &slen, &l); 1059193141Sdougb if (e) 1060193141Sdougb return (e); 1061193141Sdougb p += l; 1062193141Sdougb len -= l; 1063193141Sdougb ret += l; 1064193141Sdougb if (len < slen) 1065193141Sdougb return (ASN1_OVERRUN); 1066193141Sdougb 1067193141Sdougb e = der_get_oid(p, slen, k, &l); 1068193141Sdougb if (e) 1069193141Sdougb return (e); 1070193141Sdougb p += l; 1071193141Sdougb len -= l; 1072234010Sdougb POST(p); POST(len); 1073193141Sdougb ret += l; 1074193141Sdougb if (size) 1075193141Sdougb *size = ret; 1076193141Sdougb return (0); 1077193141Sdougb} 1078193141Sdougb 1079193141Sdougbstatic int 1080193141Sdougbfix_dce(size_t reallen, size_t *len) 1081193141Sdougb{ 1082193141Sdougb if (reallen == ASN1_INDEFINITE) 1083193141Sdougb return (1); 1084193141Sdougb if (*len < reallen) 1085193141Sdougb return (-1); 1086193141Sdougb *len = reallen; 1087193141Sdougb return (0); 1088193141Sdougb} 1089193141Sdougb 1090193141Sdougb/* der_length.c */ 1091193141Sdougb 1092193141Sdougbstatic size_t 1093193141Sdougblen_unsigned(unsigned val) 1094193141Sdougb{ 1095193141Sdougb size_t ret = 0; 1096193141Sdougb 1097193141Sdougb do { 1098193141Sdougb ++ret; 1099193141Sdougb val /= 256; 1100193141Sdougb } while (val); 1101193141Sdougb return (ret); 1102193141Sdougb} 1103193141Sdougb 1104193141Sdougbstatic size_t 1105193141Sdougblength_len(size_t len) 1106193141Sdougb{ 1107225361Sdougb if (len < 128U) 1108193141Sdougb return (1); 1109193141Sdougb else 1110262706Serwin return (len_unsigned((unsigned int)len) + 1); 1111193141Sdougb} 1112193141Sdougb 1113193141Sdougb 1114193141Sdougb/* der_put.c */ 1115193141Sdougb 1116193141Sdougb/* 1117193141Sdougb * All encoding functions take a pointer `p' to first position in which to 1118193141Sdougb * write, from the right, `len' which means the maximum number of characters 1119193141Sdougb * we are able to write. The function returns the number of characters 1120193141Sdougb * written in `size' (if non-NULL). The return value is 0 or an error. 1121193141Sdougb */ 1122193141Sdougb 1123193141Sdougbstatic int 1124193141Sdougbder_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size) 1125193141Sdougb{ 1126193141Sdougb unsigned char *base = p; 1127193141Sdougb 1128193141Sdougb if (val) { 1129225361Sdougb while (len > 0U && val) { 1130193141Sdougb *p-- = val % 256; 1131193141Sdougb val /= 256; 1132193141Sdougb --len; 1133193141Sdougb } 1134193141Sdougb if (val != 0) 1135193141Sdougb return (ASN1_OVERFLOW); 1136193141Sdougb else { 1137193141Sdougb *size = base - p; 1138193141Sdougb return (0); 1139193141Sdougb } 1140225361Sdougb } else if (len < 1U) 1141193141Sdougb return (ASN1_OVERFLOW); 1142193141Sdougb else { 1143193141Sdougb *p = 0; 1144193141Sdougb *size = 1; 1145193141Sdougb return (0); 1146193141Sdougb } 1147193141Sdougb} 1148193141Sdougb 1149193141Sdougbstatic int 1150193141Sdougbder_put_int(unsigned char *p, size_t len, int val, size_t *size) 1151193141Sdougb{ 1152193141Sdougb unsigned char *base = p; 1153193141Sdougb 1154193141Sdougb if (val >= 0) { 1155193141Sdougb do { 1156225361Sdougb if (len < 1U) 1157193141Sdougb return (ASN1_OVERFLOW); 1158193141Sdougb *p-- = val % 256; 1159193141Sdougb len--; 1160193141Sdougb val /= 256; 1161193141Sdougb } while (val); 1162193141Sdougb if (p[1] >= 128) { 1163225361Sdougb if (len < 1U) 1164193141Sdougb return (ASN1_OVERFLOW); 1165193141Sdougb *p-- = 0; 1166193141Sdougb len--; 1167193141Sdougb } 1168193141Sdougb } else { 1169193141Sdougb val = ~val; 1170193141Sdougb do { 1171225361Sdougb if (len < 1U) 1172193141Sdougb return (ASN1_OVERFLOW); 1173193141Sdougb *p-- = ~(val % 256); 1174193141Sdougb len--; 1175193141Sdougb val /= 256; 1176193141Sdougb } while (val); 1177193141Sdougb if (p[1] < 128) { 1178225361Sdougb if (len < 1U) 1179193141Sdougb return (ASN1_OVERFLOW); 1180193141Sdougb *p-- = 0xff; 1181193141Sdougb len--; 1182193141Sdougb } 1183193141Sdougb } 1184193141Sdougb *size = base - p; 1185193141Sdougb return (0); 1186193141Sdougb} 1187193141Sdougb 1188193141Sdougbstatic int 1189193141Sdougbder_put_length(unsigned char *p, size_t len, size_t val, size_t *size) 1190193141Sdougb{ 1191225361Sdougb if (len < 1U) 1192193141Sdougb return (ASN1_OVERFLOW); 1193225361Sdougb if (val < 128U) { 1194262706Serwin *p = (unsigned char)val; 1195193141Sdougb *size = 1; 1196193141Sdougb return (0); 1197193141Sdougb } else { 1198193141Sdougb size_t l; 1199193141Sdougb int e; 1200193141Sdougb 1201262706Serwin e = der_put_unsigned(p, len - 1, (unsigned int)val, &l); 1202193141Sdougb if (e) 1203193141Sdougb return (e); 1204193141Sdougb p -= l; 1205262706Serwin *p = 0x80 | (unsigned char)l; 1206193141Sdougb *size = l + 1; 1207193141Sdougb return (0); 1208193141Sdougb } 1209193141Sdougb} 1210193141Sdougb 1211193141Sdougbstatic int 1212193141Sdougbder_put_octet_string(unsigned char *p, size_t len, 1213193141Sdougb const octet_string *data, size_t *size) 1214193141Sdougb{ 1215193141Sdougb if (len < data->length) 1216193141Sdougb return (ASN1_OVERFLOW); 1217193141Sdougb p -= data->length; 1218193141Sdougb len -= data->length; 1219234010Sdougb POST(len); 1220262706Serwin memmove(p + 1, data->data, data->length); 1221193141Sdougb *size = data->length; 1222193141Sdougb return (0); 1223193141Sdougb} 1224193141Sdougb 1225193141Sdougbstatic int 1226193141Sdougbder_put_oid(unsigned char *p, size_t len, 1227193141Sdougb const oid *data, size_t *size) 1228193141Sdougb{ 1229193141Sdougb unsigned char *base = p; 1230262706Serwin size_t n; 1231193141Sdougb 1232262706Serwin for (n = data->length; n >= 3u; --n) { 1233262706Serwin unsigned u = data->components[n - 1]; 1234193141Sdougb 1235225361Sdougb if (len < 1U) 1236193141Sdougb return (ASN1_OVERFLOW); 1237193141Sdougb *p-- = u % 128; 1238193141Sdougb u /= 128; 1239193141Sdougb --len; 1240193141Sdougb while (u > 0) { 1241225361Sdougb if (len < 1U) 1242193141Sdougb return (ASN1_OVERFLOW); 1243193141Sdougb *p-- = 128 + u % 128; 1244193141Sdougb u /= 128; 1245193141Sdougb --len; 1246193141Sdougb } 1247193141Sdougb } 1248225361Sdougb if (len < 1U) 1249193141Sdougb return (ASN1_OVERFLOW); 1250193141Sdougb *p-- = 40 * data->components[0] + data->components[1]; 1251193141Sdougb *size = base - p; 1252193141Sdougb return (0); 1253193141Sdougb} 1254193141Sdougb 1255193141Sdougbstatic int 1256193141Sdougbder_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, 1257193141Sdougb int tag, size_t *size) 1258193141Sdougb{ 1259225361Sdougb if (len < 1U) 1260193141Sdougb return (ASN1_OVERFLOW); 1261193141Sdougb *p = (class << 6) | (type << 5) | tag; /* XXX */ 1262193141Sdougb *size = 1; 1263193141Sdougb return (0); 1264193141Sdougb} 1265193141Sdougb 1266193141Sdougbstatic int 1267193141Sdougbder_put_length_and_tag(unsigned char *p, size_t len, size_t len_val, 1268193141Sdougb Der_class class, Der_type type, int tag, size_t *size) 1269193141Sdougb{ 1270193141Sdougb size_t ret = 0; 1271193141Sdougb size_t l; 1272193141Sdougb int e; 1273193141Sdougb 1274193141Sdougb e = der_put_length(p, len, len_val, &l); 1275193141Sdougb if (e) 1276193141Sdougb return (e); 1277193141Sdougb p -= l; 1278193141Sdougb len -= l; 1279193141Sdougb ret += l; 1280193141Sdougb e = der_put_tag(p, len, class, type, tag, &l); 1281193141Sdougb if (e) 1282193141Sdougb return (e); 1283193141Sdougb p -= l; 1284193141Sdougb len -= l; 1285234010Sdougb POST(p); POST(len); 1286193141Sdougb ret += l; 1287193141Sdougb *size = ret; 1288193141Sdougb return (0); 1289193141Sdougb} 1290193141Sdougb 1291193141Sdougbstatic int 1292204619Sdougbencode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size) 1293193141Sdougb{ 1294204619Sdougb unsigned num = *(const unsigned *)data; 1295193141Sdougb size_t ret = 0; 1296193141Sdougb size_t l; 1297193141Sdougb int e; 1298193141Sdougb 1299193141Sdougb e = der_put_int(p, len, num, &l); 1300193141Sdougb if (e) 1301193141Sdougb return (e); 1302193141Sdougb p -= l; 1303193141Sdougb len -= l; 1304193141Sdougb ret += l; 1305193141Sdougb e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); 1306193141Sdougb if (e) 1307193141Sdougb return (e); 1308193141Sdougb p -= l; 1309193141Sdougb len -= l; 1310234010Sdougb POST(p); POST(len); 1311193141Sdougb ret += l; 1312193141Sdougb *size = ret; 1313193141Sdougb return (0); 1314193141Sdougb} 1315193141Sdougb 1316193141Sdougbstatic int 1317193141Sdougbencode_octet_string(unsigned char *p, size_t len, 1318193141Sdougb const octet_string *k, size_t *size) 1319193141Sdougb{ 1320193141Sdougb size_t ret = 0; 1321193141Sdougb size_t l; 1322193141Sdougb int e; 1323193141Sdougb 1324193141Sdougb e = der_put_octet_string(p, len, k, &l); 1325193141Sdougb if (e) 1326193141Sdougb return (e); 1327193141Sdougb p -= l; 1328193141Sdougb len -= l; 1329193141Sdougb ret += l; 1330193141Sdougb e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l); 1331193141Sdougb if (e) 1332193141Sdougb return (e); 1333193141Sdougb p -= l; 1334193141Sdougb len -= l; 1335234010Sdougb POST(p); POST(len); 1336193141Sdougb ret += l; 1337193141Sdougb *size = ret; 1338193141Sdougb return (0); 1339193141Sdougb} 1340193141Sdougb 1341193141Sdougbstatic int 1342193141Sdougbencode_oid(unsigned char *p, size_t len, 1343193141Sdougb const oid *k, size_t *size) 1344193141Sdougb{ 1345193141Sdougb size_t ret = 0; 1346193141Sdougb size_t l; 1347193141Sdougb int e; 1348193141Sdougb 1349193141Sdougb e = der_put_oid(p, len, k, &l); 1350193141Sdougb if (e) 1351193141Sdougb return (e); 1352193141Sdougb p -= l; 1353193141Sdougb len -= l; 1354193141Sdougb ret += l; 1355193141Sdougb e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l); 1356193141Sdougb if (e) 1357193141Sdougb return (e); 1358193141Sdougb p -= l; 1359193141Sdougb len -= l; 1360234010Sdougb POST(p); POST(len); 1361193141Sdougb ret += l; 1362193141Sdougb *size = ret; 1363193141Sdougb return (0); 1364193141Sdougb} 1365193141Sdougb 1366193141Sdougb 1367193141Sdougb/* encapsulate.c */ 1368193141Sdougb 1369193141Sdougbstatic void 1370193141Sdougbgssapi_encap_length(size_t data_len, 1371193141Sdougb size_t *len, 1372193141Sdougb size_t *total_len, 1373193141Sdougb const gss_OID mech) 1374193141Sdougb{ 1375193141Sdougb size_t len_len; 1376193141Sdougb 1377193141Sdougb *len = 1 + 1 + mech->length + data_len; 1378193141Sdougb 1379193141Sdougb len_len = length_len(*len); 1380193141Sdougb 1381193141Sdougb *total_len = 1 + len_len + *len; 1382193141Sdougb} 1383193141Sdougb 1384193141Sdougbstatic u_char * 1385193141Sdougbgssapi_mech_make_header(u_char *p, 1386193141Sdougb size_t len, 1387193141Sdougb const gss_OID mech) 1388193141Sdougb{ 1389193141Sdougb int e; 1390193141Sdougb size_t len_len, foo; 1391193141Sdougb 1392193141Sdougb *p++ = 0x60; 1393193141Sdougb len_len = length_len(len); 1394193141Sdougb e = der_put_length(p + len_len - 1, len_len, len, &foo); 1395193141Sdougb if (e || foo != len_len) 1396193141Sdougb return (NULL); 1397193141Sdougb p += len_len; 1398193141Sdougb *p++ = 0x06; 1399193141Sdougb *p++ = mech->length; 1400262706Serwin memmove(p, mech->elements, mech->length); 1401193141Sdougb p += mech->length; 1402193141Sdougb return (p); 1403193141Sdougb} 1404193141Sdougb 1405193141Sdougb/* 1406193141Sdougb * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. 1407193141Sdougb */ 1408193141Sdougb 1409193141Sdougbstatic OM_uint32 1410193141Sdougbgssapi_spnego_encapsulate(OM_uint32 * minor_status, 1411193141Sdougb unsigned char *buf, 1412193141Sdougb size_t buf_size, 1413193141Sdougb gss_buffer_t output_token, 1414193141Sdougb const gss_OID mech) 1415193141Sdougb{ 1416193141Sdougb size_t len, outer_len; 1417193141Sdougb u_char *p; 1418193141Sdougb 1419193141Sdougb gssapi_encap_length(buf_size, &len, &outer_len, mech); 1420193141Sdougb 1421193141Sdougb output_token->length = outer_len; 1422193141Sdougb output_token->value = malloc(outer_len); 1423193141Sdougb if (output_token->value == NULL) { 1424193141Sdougb *minor_status = ENOMEM; 1425193141Sdougb return (GSS_S_FAILURE); 1426193141Sdougb } 1427193141Sdougb p = gssapi_mech_make_header(output_token->value, len, mech); 1428193141Sdougb if (p == NULL) { 1429225361Sdougb if (output_token->length != 0U) 1430193141Sdougb gss_release_buffer(minor_status, output_token); 1431193141Sdougb return (GSS_S_FAILURE); 1432193141Sdougb } 1433262706Serwin memmove(p, buf, buf_size); 1434193141Sdougb return (GSS_S_COMPLETE); 1435193141Sdougb} 1436193141Sdougb 1437193141Sdougb/* init_sec_context.c */ 1438193141Sdougb/* 1439193141Sdougb * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly 1440193141Sdougb * based on Heimdal code) 1441193141Sdougb */ 1442193141Sdougb 1443193141Sdougbstatic int 1444193141Sdougbadd_mech(MechTypeList * mech_list, gss_OID mech) 1445193141Sdougb{ 1446193141Sdougb MechType *tmp; 1447193141Sdougb int ret; 1448193141Sdougb 1449193141Sdougb tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp)); 1450193141Sdougb if (tmp == NULL) 1451193141Sdougb return (ENOMEM); 1452193141Sdougb mech_list->val = tmp; 1453193141Sdougb 1454193141Sdougb ret = der_get_oid(mech->elements, mech->length, 1455193141Sdougb &mech_list->val[mech_list->len], NULL); 1456193141Sdougb if (ret) 1457193141Sdougb return (ret); 1458193141Sdougb 1459193141Sdougb mech_list->len++; 1460193141Sdougb return (0); 1461193141Sdougb} 1462193141Sdougb 1463193141Sdougb/* 1464193141Sdougb * return the length of the mechanism in token or -1 1465193141Sdougb * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN 1466193141Sdougb */ 1467193141Sdougb 1468193141Sdougbstatic ssize_t 1469193141Sdougbgssapi_krb5_get_mech(const u_char *ptr, 1470193141Sdougb size_t total_len, 1471193141Sdougb const u_char **mech_ret) 1472193141Sdougb{ 1473193141Sdougb size_t len, len_len, mech_len, foo; 1474193141Sdougb const u_char *p = ptr; 1475193141Sdougb int e; 1476193141Sdougb 1477225361Sdougb if (total_len < 1U) 1478193141Sdougb return (-1); 1479193141Sdougb if (*p++ != 0x60) 1480193141Sdougb return (-1); 1481193141Sdougb e = der_get_length (p, total_len - 1, &len, &len_len); 1482193141Sdougb if (e || 1 + len_len + len != total_len) 1483193141Sdougb return (-1); 1484193141Sdougb p += len_len; 1485193141Sdougb if (*p++ != 0x06) 1486193141Sdougb return (-1); 1487193141Sdougb e = der_get_length (p, total_len - 1 - len_len - 1, 1488193141Sdougb &mech_len, &foo); 1489193141Sdougb if (e) 1490193141Sdougb return (-1); 1491193141Sdougb p += foo; 1492193141Sdougb *mech_ret = p; 1493193141Sdougb return (mech_len); 1494193141Sdougb} 1495193141Sdougb 1496193141Sdougbstatic OM_uint32 1497193141Sdougbspnego_initial(OM_uint32 *minor_status, 1498193141Sdougb const gss_cred_id_t initiator_cred_handle, 1499193141Sdougb gss_ctx_id_t *context_handle, 1500193141Sdougb const gss_name_t target_name, 1501193141Sdougb const gss_OID mech_type, 1502193141Sdougb OM_uint32 req_flags, 1503193141Sdougb OM_uint32 time_req, 1504193141Sdougb const gss_channel_bindings_t input_chan_bindings, 1505193141Sdougb const gss_buffer_t input_token, 1506193141Sdougb gss_OID *actual_mech_type, 1507193141Sdougb gss_buffer_t output_token, 1508193141Sdougb OM_uint32 *ret_flags, 1509193141Sdougb OM_uint32 *time_rec) 1510193141Sdougb{ 1511193141Sdougb NegTokenInit token_init; 1512193141Sdougb OM_uint32 major_status, minor_status2; 1513193141Sdougb gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER; 1514193141Sdougb unsigned char *buf = NULL; 1515193141Sdougb size_t buf_size; 1516193141Sdougb size_t len; 1517193141Sdougb int ret; 1518193141Sdougb 1519193141Sdougb (void)mech_type; 1520193141Sdougb 1521193141Sdougb memset(&token_init, 0, sizeof(token_init)); 1522193141Sdougb 1523193141Sdougb ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH); 1524193141Sdougb if (ret) { 1525193141Sdougb *minor_status = ret; 1526193141Sdougb ret = GSS_S_FAILURE; 1527193141Sdougb goto end; 1528193141Sdougb } 1529193141Sdougb 1530193141Sdougb major_status = gss_init_sec_context(minor_status, 1531193141Sdougb initiator_cred_handle, 1532193141Sdougb context_handle, 1533193141Sdougb target_name, 1534193141Sdougb GSS_KRB5_MECH, 1535193141Sdougb req_flags, 1536193141Sdougb time_req, 1537193141Sdougb input_chan_bindings, 1538193141Sdougb input_token, 1539193141Sdougb actual_mech_type, 1540193141Sdougb &krb5_output_token, 1541193141Sdougb ret_flags, 1542193141Sdougb time_rec); 1543193141Sdougb if (GSS_ERROR(major_status)) { 1544193141Sdougb ret = major_status; 1545193141Sdougb goto end; 1546193141Sdougb } 1547225361Sdougb if (krb5_output_token.length > 0U) { 1548193141Sdougb token_init.mechToken = malloc(sizeof(*token_init.mechToken)); 1549193141Sdougb if (token_init.mechToken == NULL) { 1550193141Sdougb *minor_status = ENOMEM; 1551193141Sdougb ret = GSS_S_FAILURE; 1552193141Sdougb goto end; 1553193141Sdougb } 1554193141Sdougb token_init.mechToken->data = krb5_output_token.value; 1555193141Sdougb token_init.mechToken->length = krb5_output_token.length; 1556193141Sdougb } 1557193141Sdougb /* 1558193141Sdougb * The MS implementation of SPNEGO seems to not like the mechListMIC 1559193141Sdougb * field, so we omit it (it's optional anyway) 1560193141Sdougb */ 1561193141Sdougb 1562193141Sdougb buf_size = 1024; 1563193141Sdougb buf = malloc(buf_size); 1564254402Serwin if (buf == NULL) { 1565254402Serwin *minor_status = ENOMEM; 1566254402Serwin ret = GSS_S_FAILURE; 1567254402Serwin goto end; 1568254402Serwin } 1569193141Sdougb 1570193141Sdougb do { 1571193141Sdougb ret = encode_NegTokenInit(buf + buf_size - 1, 1572193141Sdougb buf_size, 1573193141Sdougb &token_init, &len); 1574193141Sdougb if (ret == 0) { 1575193141Sdougb size_t tmp; 1576193141Sdougb 1577193141Sdougb ret = der_put_length_and_tag(buf + buf_size - len - 1, 1578193141Sdougb buf_size - len, 1579193141Sdougb len, 1580193141Sdougb ASN1_C_CONTEXT, 1581193141Sdougb CONS, 1582193141Sdougb 0, 1583193141Sdougb &tmp); 1584193141Sdougb if (ret == 0) 1585193141Sdougb len += tmp; 1586193141Sdougb } 1587193141Sdougb if (ret) { 1588193141Sdougb if (ret == ASN1_OVERFLOW) { 1589193141Sdougb u_char *tmp; 1590193141Sdougb 1591193141Sdougb buf_size *= 2; 1592193141Sdougb tmp = realloc(buf, buf_size); 1593193141Sdougb if (tmp == NULL) { 1594193141Sdougb *minor_status = ENOMEM; 1595193141Sdougb ret = GSS_S_FAILURE; 1596193141Sdougb goto end; 1597193141Sdougb } 1598193141Sdougb buf = tmp; 1599193141Sdougb } else { 1600193141Sdougb *minor_status = ret; 1601193141Sdougb ret = GSS_S_FAILURE; 1602193141Sdougb goto end; 1603193141Sdougb } 1604193141Sdougb } 1605193141Sdougb } while (ret == ASN1_OVERFLOW); 1606193141Sdougb 1607193141Sdougb ret = gssapi_spnego_encapsulate(minor_status, 1608193141Sdougb buf + buf_size - len, len, 1609193141Sdougb output_token, GSS_SPNEGO_MECH); 1610193141Sdougb if (ret == GSS_S_COMPLETE) 1611193141Sdougb ret = major_status; 1612193141Sdougb 1613193141Sdougbend: 1614193141Sdougb if (token_init.mechToken != NULL) { 1615193141Sdougb free(token_init.mechToken); 1616193141Sdougb token_init.mechToken = NULL; 1617193141Sdougb } 1618193141Sdougb free_NegTokenInit(&token_init); 1619225361Sdougb if (krb5_output_token.length != 0U) 1620193141Sdougb gss_release_buffer(&minor_status2, &krb5_output_token); 1621193141Sdougb if (buf) 1622193141Sdougb free(buf); 1623193141Sdougb 1624193141Sdougb return (ret); 1625193141Sdougb} 1626193141Sdougb 1627193141Sdougbstatic OM_uint32 1628193141Sdougbspnego_reply(OM_uint32 *minor_status, 1629193141Sdougb const gss_cred_id_t initiator_cred_handle, 1630193141Sdougb gss_ctx_id_t *context_handle, 1631193141Sdougb const gss_name_t target_name, 1632193141Sdougb const gss_OID mech_type, 1633193141Sdougb OM_uint32 req_flags, 1634193141Sdougb OM_uint32 time_req, 1635193141Sdougb const gss_channel_bindings_t input_chan_bindings, 1636193141Sdougb const gss_buffer_t input_token, 1637193141Sdougb gss_OID *actual_mech_type, 1638193141Sdougb gss_buffer_t output_token, 1639193141Sdougb OM_uint32 *ret_flags, 1640193141Sdougb OM_uint32 *time_rec) 1641193141Sdougb{ 1642193141Sdougb OM_uint32 ret; 1643193141Sdougb NegTokenResp resp; 1644193141Sdougb unsigned char *buf; 1645193141Sdougb size_t buf_size; 1646193141Sdougb u_char oidbuf[17]; 1647193141Sdougb size_t oidlen; 1648193141Sdougb gss_buffer_desc sub_token; 1649193141Sdougb ssize_t mech_len; 1650193141Sdougb const u_char *p; 1651193141Sdougb size_t len, taglen; 1652193141Sdougb 1653193141Sdougb (void)mech_type; 1654193141Sdougb 1655193141Sdougb output_token->length = 0; 1656193141Sdougb output_token->value = NULL; 1657193141Sdougb 1658193141Sdougb /* 1659193141Sdougb * SPNEGO doesn't include gss wrapping on SubsequentContextToken 1660193141Sdougb * like the Kerberos 5 mech does. But lets check for it anyway. 1661193141Sdougb */ 1662193141Sdougb 1663193141Sdougb mech_len = gssapi_krb5_get_mech(input_token->value, 1664193141Sdougb input_token->length, 1665193141Sdougb &p); 1666193141Sdougb 1667193141Sdougb if (mech_len < 0) { 1668193141Sdougb buf = input_token->value; 1669193141Sdougb buf_size = input_token->length; 1670193141Sdougb } else if ((size_t)mech_len == GSS_KRB5_MECH->length && 1671193141Sdougb memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0) 1672193141Sdougb return (gss_init_sec_context(minor_status, 1673193141Sdougb initiator_cred_handle, 1674193141Sdougb context_handle, 1675193141Sdougb target_name, 1676193141Sdougb GSS_KRB5_MECH, 1677193141Sdougb req_flags, 1678193141Sdougb time_req, 1679193141Sdougb input_chan_bindings, 1680193141Sdougb input_token, 1681193141Sdougb actual_mech_type, 1682193141Sdougb output_token, 1683193141Sdougb ret_flags, 1684193141Sdougb time_rec)); 1685193141Sdougb else if ((size_t)mech_len == GSS_SPNEGO_MECH->length && 1686193141Sdougb memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) { 1687193141Sdougb ret = gssapi_spnego_decapsulate(minor_status, 1688193141Sdougb input_token, 1689193141Sdougb &buf, 1690193141Sdougb &buf_size, 1691193141Sdougb GSS_SPNEGO_MECH); 1692193141Sdougb if (ret) 1693193141Sdougb return (ret); 1694193141Sdougb } else 1695193141Sdougb return (GSS_S_BAD_MECH); 1696193141Sdougb 1697193141Sdougb ret = der_match_tag_and_length(buf, buf_size, 1698193141Sdougb ASN1_C_CONTEXT, CONS, 1, &len, &taglen); 1699193141Sdougb if (ret) 1700193141Sdougb return (ret); 1701193141Sdougb 1702193141Sdougb if(len > buf_size - taglen) 1703193141Sdougb return (ASN1_OVERRUN); 1704193141Sdougb 1705193141Sdougb ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL); 1706193141Sdougb if (ret) { 1707254402Serwin free_NegTokenResp(&resp); 1708193141Sdougb *minor_status = ENOMEM; 1709193141Sdougb return (GSS_S_FAILURE); 1710193141Sdougb } 1711193141Sdougb 1712193141Sdougb if (resp.negState == NULL || 1713193141Sdougb *(resp.negState) == reject || 1714193141Sdougb resp.supportedMech == NULL) { 1715193141Sdougb free_NegTokenResp(&resp); 1716193141Sdougb return (GSS_S_BAD_MECH); 1717193141Sdougb } 1718193141Sdougb 1719193141Sdougb ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1, 1720193141Sdougb sizeof(oidbuf), 1721193141Sdougb resp.supportedMech, 1722193141Sdougb &oidlen); 1723193141Sdougb if (ret || oidlen != GSS_KRB5_MECH->length || 1724193141Sdougb memcmp(oidbuf + sizeof(oidbuf) - oidlen, 1725193141Sdougb GSS_KRB5_MECH->elements, 1726193141Sdougb oidlen) != 0) { 1727193141Sdougb free_NegTokenResp(&resp); 1728193141Sdougb return GSS_S_BAD_MECH; 1729193141Sdougb } 1730193141Sdougb 1731193141Sdougb if (resp.responseToken != NULL) { 1732193141Sdougb sub_token.length = resp.responseToken->length; 1733193141Sdougb sub_token.value = resp.responseToken->data; 1734193141Sdougb } else { 1735193141Sdougb sub_token.length = 0; 1736193141Sdougb sub_token.value = NULL; 1737193141Sdougb } 1738193141Sdougb 1739193141Sdougb ret = gss_init_sec_context(minor_status, 1740193141Sdougb initiator_cred_handle, 1741193141Sdougb context_handle, 1742193141Sdougb target_name, 1743193141Sdougb GSS_KRB5_MECH, 1744193141Sdougb req_flags, 1745193141Sdougb time_req, 1746193141Sdougb input_chan_bindings, 1747193141Sdougb &sub_token, 1748193141Sdougb actual_mech_type, 1749193141Sdougb output_token, 1750193141Sdougb ret_flags, 1751193141Sdougb time_rec); 1752193141Sdougb if (ret) { 1753193141Sdougb free_NegTokenResp(&resp); 1754193141Sdougb return (ret); 1755193141Sdougb } 1756193141Sdougb 1757193141Sdougb /* 1758193141Sdougb * XXXSRA I don't think this limited implementation ever needs 1759193141Sdougb * to check the MIC -- our preferred mechanism (Kerberos) 1760193141Sdougb * authenticates its own messages and is the only mechanism 1761193141Sdougb * we'll accept, so if the mechanism negotiation completes 1762193141Sdougb * successfully, we don't need the MIC. See RFC 4178. 1763193141Sdougb */ 1764193141Sdougb 1765193141Sdougb free_NegTokenResp(&resp); 1766193141Sdougb return (ret); 1767193141Sdougb} 1768193141Sdougb 1769193141Sdougb 1770193141Sdougb 1771193141SdougbOM_uint32 1772193141Sdougbgss_init_sec_context_spnego(OM_uint32 *minor_status, 1773193141Sdougb const gss_cred_id_t initiator_cred_handle, 1774193141Sdougb gss_ctx_id_t *context_handle, 1775193141Sdougb const gss_name_t target_name, 1776193141Sdougb const gss_OID mech_type, 1777193141Sdougb OM_uint32 req_flags, 1778193141Sdougb OM_uint32 time_req, 1779193141Sdougb const gss_channel_bindings_t input_chan_bindings, 1780193141Sdougb const gss_buffer_t input_token, 1781193141Sdougb gss_OID *actual_mech_type, 1782193141Sdougb gss_buffer_t output_token, 1783193141Sdougb OM_uint32 *ret_flags, 1784193141Sdougb OM_uint32 *time_rec) 1785193141Sdougb{ 1786193141Sdougb /* Dirty trick to suppress compiler warnings */ 1787193141Sdougb 1788193141Sdougb /* Figure out whether we're starting over or processing a reply */ 1789193141Sdougb 1790225361Sdougb if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U) 1791193141Sdougb return (spnego_initial(minor_status, 1792193141Sdougb initiator_cred_handle, 1793193141Sdougb context_handle, 1794193141Sdougb target_name, 1795193141Sdougb mech_type, 1796193141Sdougb req_flags, 1797193141Sdougb time_req, 1798193141Sdougb input_chan_bindings, 1799193141Sdougb input_token, 1800193141Sdougb actual_mech_type, 1801193141Sdougb output_token, 1802193141Sdougb ret_flags, 1803193141Sdougb time_rec)); 1804193141Sdougb else 1805193141Sdougb return (spnego_reply(minor_status, 1806193141Sdougb initiator_cred_handle, 1807193141Sdougb context_handle, 1808193141Sdougb target_name, 1809193141Sdougb mech_type, 1810193141Sdougb req_flags, 1811193141Sdougb time_req, 1812193141Sdougb input_chan_bindings, 1813193141Sdougb input_token, 1814193141Sdougb actual_mech_type, 1815193141Sdougb output_token, 1816193141Sdougb ret_flags, 1817193141Sdougb time_rec)); 1818193141Sdougb} 1819193141Sdougb 1820193141Sdougb#endif /* GSSAPI */ 1821