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