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