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