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