2 * Copyright (C) 2006-2009 Internet Systems Consortium, Inc. ("ISC")
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.
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.
17 /* $Id: spnego.c,v 1.5.128.7 2009/07/21 07:29:23 marka Exp $ */
21 * Portable SPNEGO implementation.
23 * This is part of a portable implementation of the SPNEGO protocol
24 * (RFCs 2478 and 4178). This implementation uses the RFC 4178 ASN.1
25 * module but is not a full implementation of the RFC 4178 protocol;
26 * at the moment, we only support GSS-TSIG with Kerberos
27 * authentication, so we only need enough of the SPNEGO protocol to
30 * The files that make up this portable SPNEGO implementation are:
31 * \li spnego.c (this file)
32 * \li spnego.h (API SPNEGO exports to the rest of lib/dns)
33 * \li spnego.asn1 (SPNEGO ASN.1 module)
34 * \li spnego_asn1.c (routines generated from spngo.asn1)
35 * \li spnego_asn1.pl (perl script to generate spnego_asn1.c)
37 * Everything but the functions exported in spnego.h is static, to
38 * avoid possible conflicts with other libraries (particularly Heimdal,
39 * since much of this code comes from Heimdal by way of mod_auth_kerb).
41 * spnego_asn1.c is shipped as part of lib/dns because generating it
42 * requires both Perl and the Heimdal ASN.1 compiler. See
43 * spnego_asn1.pl for further details. We've tried to eliminate all
44 * compiler warnings from the generated code, but you may see a few
45 * when using a compiler version we haven't tested yet.
49 * Portions of this code were derived from mod_auth_kerb and Heimdal.
50 * These packages are available from:
52 * http://modauthkerb.sourceforge.net/
53 * http://www.pdc.kth.se/heimdal/
55 * and were released under the following licenses:
57 * ----------------------------------------------------------------
59 * Copyright (c) 2004 Masarykova universita
60 * (Masaryk University, Brno, Czech Republic)
61 * All rights reserved.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions are met:
66 * 1. Redistributions of source code must retain the above copyright notice,
67 * this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
73 * 3. Neither the name of the University nor the names of its contributors may
74 * be used to endorse or promote products derived from this software
75 * without specific prior written permission.
77 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
78 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
81 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
82 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
83 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
84 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
85 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
86 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
87 * POSSIBILITY OF SUCH DAMAGE.
89 * ----------------------------------------------------------------
91 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
92 * (Royal Institute of Technology, Stockholm, Sweden).
93 * All rights reserved.
95 * Redistribution and use in source and binary forms, with or without
96 * modification, are permitted provided that the following conditions
99 * 1. Redistributions of source code must retain the above copyright
100 * notice, this list of conditions and the following disclaimer.
102 * 2. Redistributions in binary form must reproduce the above copyright
103 * notice, this list of conditions and the following disclaimer in the
104 * documentation and/or other materials provided with the distribution.
106 * 3. Neither the name of the Institute nor the names of its contributors
107 * may be used to endorse or promote products derived from this software
108 * without specific prior written permission.
110 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
111 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
112 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
113 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
114 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
115 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
116 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
117 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
118 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
119 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
124 * XXXSRA We should omit this file entirely in Makefile.in via autoconf,
125 * but this will keep it from generating errors until that's written.
131 * XXXSRA Some of the following files are almost certainly unnecessary,
132 * but using this list (borrowed from gssapictx.c) gets rid of some
133 * whacky compilation errors when building with MSVC and should be
134 * harmless in any case.
142 #include <isc/buffer.h>
144 #include <isc/entropy.h>
147 #include <isc/once.h>
148 #include <isc/random.h>
149 #include <isc/string.h>
150 #include <isc/time.h>
151 #include <isc/util.h>
153 #include <dns/fixedname.h>
154 #include <dns/name.h>
155 #include <dns/rdata.h>
156 #include <dns/rdataclass.h>
157 #include <dns/result.h>
158 #include <dns/types.h>
159 #include <dns/keyvalues.h>
162 #include <dst/gssapi.h>
163 #include <dst/result.h>
165 #include "dst_internal.h"
173 /* Generated from ../../../lib/asn1/asn1_err.et */
175 typedef enum asn1_error_number
{
176 ASN1_BAD_TIMEFORMAT
= 1859794432,
177 ASN1_MISSING_FIELD
= 1859794433,
178 ASN1_MISPLACED_FIELD
= 1859794434,
179 ASN1_TYPE_MISMATCH
= 1859794435,
180 ASN1_OVERFLOW
= 1859794436,
181 ASN1_OVERRUN
= 1859794437,
182 ASN1_BAD_ID
= 1859794438,
183 ASN1_BAD_LENGTH
= 1859794439,
184 ASN1_BAD_FORMAT
= 1859794440,
185 ASN1_PARSE_ERROR
= 1859794441
188 #define ERROR_TABLE_BASE_asn1 1859794432
190 #define __asn1_common_definitions__
192 typedef struct octet_string
{
197 typedef char *general_string
;
199 typedef char *utf8_string
;
203 unsigned *components
;
209 ASN1_C_UNIV
= 0, ASN1_C_APPL
= 1,
210 ASN1_C_CONTEXT
= 2, ASN1_C_PRIVATE
= 3
229 UT_PrintableString
= 19,
232 UT_GeneralizedTime
= 24,
233 UT_VisibleString
= 26,
234 UT_GeneralString
= 27
237 #define ASN1_INDEFINITE 0xdce0deed
240 der_get_length(const unsigned char *p
, size_t len
,
241 size_t * val
, size_t * size
);
244 der_get_octet_string(const unsigned char *p
, size_t len
,
245 octet_string
* data
, size_t * size
);
247 der_get_oid(const unsigned char *p
, size_t len
,
248 oid
* data
, size_t * size
);
250 der_get_tag(const unsigned char *p
, size_t len
,
251 Der_class
* class, Der_type
* type
,
252 int *tag
, size_t * size
);
255 der_match_tag(const unsigned char *p
, size_t len
,
256 Der_class
class, Der_type type
,
257 int tag
, size_t * size
);
259 der_match_tag_and_length(const unsigned char *p
, size_t len
,
260 Der_class
class, Der_type type
, int tag
,
261 size_t * length_ret
, size_t * size
);
264 decode_oid(const unsigned char *p
, size_t len
,
265 oid
* k
, size_t * size
);
268 decode_enumerated(const unsigned char *p
, size_t len
, void *num
, size_t *size
);
271 decode_octet_string(const unsigned char *, size_t, octet_string
*, size_t *);
274 der_put_int(unsigned char *p
, size_t len
, int val
, size_t *);
277 der_put_length(unsigned char *p
, size_t len
, size_t val
, size_t *);
280 der_put_octet_string(unsigned char *p
, size_t len
,
281 const octet_string
* data
, size_t *);
283 der_put_oid(unsigned char *p
, size_t len
,
284 const oid
* data
, size_t * size
);
286 der_put_tag(unsigned char *p
, size_t len
, Der_class
class, Der_type type
,
289 der_put_length_and_tag(unsigned char *, size_t, size_t,
290 Der_class
, Der_type
, int, size_t *);
293 encode_enumerated(unsigned char *p
, size_t len
, const void *data
, size_t *);
296 encode_octet_string(unsigned char *p
, size_t len
,
297 const octet_string
* k
, size_t *);
299 encode_oid(unsigned char *p
, size_t len
,
300 const oid
* k
, size_t *);
303 free_octet_string(octet_string
* k
);
309 length_len(size_t len
);
312 fix_dce(size_t reallen
, size_t * len
);
315 * Include stuff generated by the ASN.1 compiler.
318 #include "spnego_asn1.c"
320 static unsigned char gss_krb5_mech_oid_bytes
[] = {
321 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
324 static gss_OID_desc gss_krb5_mech_oid_desc
= {
325 sizeof(gss_krb5_mech_oid_bytes
),
326 gss_krb5_mech_oid_bytes
329 static gss_OID GSS_KRB5_MECH
= &gss_krb5_mech_oid_desc
;
331 static unsigned char gss_mskrb5_mech_oid_bytes
[] = {
332 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
335 static gss_OID_desc gss_mskrb5_mech_oid_desc
= {
336 sizeof(gss_mskrb5_mech_oid_bytes
),
337 gss_mskrb5_mech_oid_bytes
340 static gss_OID GSS_MSKRB5_MECH
= &gss_mskrb5_mech_oid_desc
;
342 static unsigned char gss_spnego_mech_oid_bytes
[] = {
343 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
346 static gss_OID_desc gss_spnego_mech_oid_desc
= {
347 sizeof(gss_spnego_mech_oid_bytes
),
348 gss_spnego_mech_oid_bytes
351 static gss_OID GSS_SPNEGO_MECH
= &gss_spnego_mech_oid_desc
;
353 /* spnegokrb5_locl.h */
356 gssapi_spnego_encapsulate(OM_uint32
*,
363 gssapi_spnego_decapsulate(OM_uint32
*,
369 /* mod_auth_kerb.c */
372 cmp_gss_type(gss_buffer_t token
, gss_OID oid
)
377 if (token
->length
== 0)
378 return (GSS_S_DEFECTIVE_TOKEN
);
382 return (GSS_S_DEFECTIVE_TOKEN
);
385 if ((len
& 0x7f) > 4)
386 return (GSS_S_DEFECTIVE_TOKEN
);
390 return (GSS_S_DEFECTIVE_TOKEN
);
392 if (((OM_uint32
) *p
++) != oid
->length
)
393 return (GSS_S_DEFECTIVE_TOKEN
);
395 return (memcmp(p
, oid
->elements
, oid
->length
));
398 /* accept_sec_context.c */
400 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
401 * based on Heimdal code)
405 code_NegTokenArg(OM_uint32
* minor_status
,
406 const NegTokenResp
* resp
,
407 unsigned char **outbuf
,
408 size_t * outbuf_size
)
412 size_t buf_size
, buf_len
;
415 buf
= malloc(buf_size
);
417 *minor_status
= ENOMEM
;
418 return (GSS_S_FAILURE
);
421 ret
= encode_NegTokenResp(buf
+ buf_size
- 1,
427 ret
= der_put_length_and_tag(buf
+ buf_size
- buf_len
- 1,
438 if (ret
== ASN1_OVERFLOW
) {
442 tmp
= realloc(buf
, buf_size
);
444 *minor_status
= ENOMEM
;
446 return (GSS_S_FAILURE
);
452 return (GSS_S_FAILURE
);
455 } while (ret
== ASN1_OVERFLOW
);
457 *outbuf
= malloc(buf_len
);
458 if (*outbuf
== NULL
) {
459 *minor_status
= ENOMEM
;
461 return (GSS_S_FAILURE
);
463 memcpy(*outbuf
, buf
+ buf_size
- buf_len
, buf_len
);
464 *outbuf_size
= buf_len
;
468 return (GSS_S_COMPLETE
);
472 send_reject(OM_uint32
* minor_status
,
473 gss_buffer_t output_token
)
478 resp
.negState
= malloc(sizeof(*resp
.negState
));
479 if (resp
.negState
== NULL
) {
480 *minor_status
= ENOMEM
;
481 return (GSS_S_FAILURE
);
483 *(resp
.negState
) = reject
;
485 resp
.supportedMech
= NULL
;
486 resp
.responseToken
= NULL
;
487 resp
.mechListMIC
= NULL
;
489 ret
= code_NegTokenArg(minor_status
, &resp
,
490 (unsigned char **)&output_token
->value
,
491 &output_token
->length
);
492 free_NegTokenResp(&resp
);
496 return (GSS_S_BAD_MECH
);
500 send_accept(OM_uint32
* minor_status
,
501 gss_buffer_t output_token
,
502 gss_buffer_t mech_token
,
508 memset(&resp
, 0, sizeof(resp
));
509 resp
.negState
= malloc(sizeof(*resp
.negState
));
510 if (resp
.negState
== NULL
) {
511 *minor_status
= ENOMEM
;
512 return (GSS_S_FAILURE
);
514 *(resp
.negState
) = accept_completed
;
516 resp
.supportedMech
= malloc(sizeof(*resp
.supportedMech
));
517 if (resp
.supportedMech
== NULL
) {
518 free_NegTokenResp(&resp
);
519 *minor_status
= ENOMEM
;
520 return (GSS_S_FAILURE
);
522 ret
= der_get_oid(pref
->elements
,
527 free_NegTokenResp(&resp
);
528 *minor_status
= ENOMEM
;
529 return (GSS_S_FAILURE
);
531 if (mech_token
!= NULL
&& mech_token
->length
!= 0) {
532 resp
.responseToken
= malloc(sizeof(*resp
.responseToken
));
533 if (resp
.responseToken
== NULL
) {
534 free_NegTokenResp(&resp
);
535 *minor_status
= ENOMEM
;
536 return (GSS_S_FAILURE
);
538 resp
.responseToken
->length
= mech_token
->length
;
539 resp
.responseToken
->data
= mech_token
->value
;
542 ret
= code_NegTokenArg(minor_status
, &resp
,
543 (unsigned char **)&output_token
->value
,
544 &output_token
->length
);
545 if (resp
.responseToken
!= NULL
) {
546 free(resp
.responseToken
);
547 resp
.responseToken
= NULL
;
549 free_NegTokenResp(&resp
);
553 return (GSS_S_COMPLETE
);
557 gss_accept_sec_context_spnego(OM_uint32
*minor_status
,
558 gss_ctx_id_t
*context_handle
,
559 const gss_cred_id_t acceptor_cred_handle
,
560 const gss_buffer_t input_token_buffer
,
561 const gss_channel_bindings_t input_chan_bindings
,
562 gss_name_t
*src_name
,
564 gss_buffer_t output_token
,
565 OM_uint32
*ret_flags
,
567 gss_cred_id_t
*delegated_cred_handle
)
569 NegTokenInit init_token
;
570 OM_uint32 major_status
;
571 OM_uint32 minor_status2
;
572 gss_buffer_desc ibuf
, obuf
;
573 gss_buffer_t ot
= NULL
;
574 gss_OID pref
= GSS_KRB5_MECH
;
577 size_t len
, taglen
, ni_len
;
583 * Before doing anything else, see whether this is a SPNEGO
584 * PDU. If not, dispatch to the GSSAPI library and get out.
587 if (cmp_gss_type(input_token_buffer
, GSS_SPNEGO_MECH
))
588 return (gss_accept_sec_context(minor_status
,
590 acceptor_cred_handle
,
598 delegated_cred_handle
));
601 * If we get here, it's SPNEGO.
604 memset(&init_token
, 0, sizeof(init_token
));
606 ret
= gssapi_spnego_decapsulate(minor_status
, input_token_buffer
,
607 &buf
, &buf_size
, GSS_SPNEGO_MECH
);
611 ret
= der_match_tag_and_length(buf
, buf_size
, ASN1_C_CONTEXT
, CONS
,
616 ret
= decode_NegTokenInit(buf
+ taglen
, len
, &init_token
, &ni_len
);
618 *minor_status
= EINVAL
; /* XXX */
619 return (GSS_S_DEFECTIVE_TOKEN
);
622 for (i
= 0; !found
&& i
< init_token
.mechTypes
.len
; ++i
) {
623 unsigned char mechbuf
[17];
626 ret
= der_put_oid(mechbuf
+ sizeof(mechbuf
) - 1,
628 &init_token
.mechTypes
.val
[i
],
631 return (GSS_S_DEFECTIVE_TOKEN
);
632 if (mech_len
== GSS_KRB5_MECH
->length
&&
633 memcmp(GSS_KRB5_MECH
->elements
,
634 mechbuf
+ sizeof(mechbuf
) - mech_len
,
639 if (mech_len
== GSS_MSKRB5_MECH
->length
&&
640 memcmp(GSS_MSKRB5_MECH
->elements
,
641 mechbuf
+ sizeof(mechbuf
) - mech_len
,
645 pref
= GSS_MSKRB5_MECH
;
651 return (send_reject(minor_status
, output_token
));
653 if (i
== 0 && init_token
.mechToken
!= NULL
) {
654 ibuf
.length
= init_token
.mechToken
->length
;
655 ibuf
.value
= init_token
.mechToken
->data
;
657 major_status
= gss_accept_sec_context(minor_status
,
659 acceptor_cred_handle
,
667 delegated_cred_handle
);
668 if (GSS_ERROR(major_status
)) {
669 send_reject(&minor_status2
, output_token
);
670 return (major_status
);
674 ret
= send_accept(&minor_status2
, output_token
, ot
, pref
);
675 if (ot
!= NULL
&& ot
->length
!= 0)
676 gss_release_buffer(&minor_status2
, ot
);
684 gssapi_verify_mech_header(u_char
** str
,
688 size_t len
, len_len
, mech_len
, foo
;
693 return (GSS_S_DEFECTIVE_TOKEN
);
695 return (GSS_S_DEFECTIVE_TOKEN
);
696 e
= der_get_length(p
, total_len
- 1, &len
, &len_len
);
697 if (e
|| 1 + len_len
+ len
!= total_len
)
698 return (GSS_S_DEFECTIVE_TOKEN
);
701 return (GSS_S_DEFECTIVE_TOKEN
);
702 e
= der_get_length(p
, total_len
- 1 - len_len
- 1,
705 return (GSS_S_DEFECTIVE_TOKEN
);
707 if (mech_len
!= mech
->length
)
708 return (GSS_S_BAD_MECH
);
709 if (memcmp(p
, mech
->elements
, mech
->length
) != 0)
710 return (GSS_S_BAD_MECH
);
713 return (GSS_S_COMPLETE
);
717 * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
718 * not copy data, so just free `in_token'.
722 gssapi_spnego_decapsulate(OM_uint32
*minor_status
,
723 gss_buffer_t input_token_buffer
,
731 p
= input_token_buffer
->value
;
732 ret
= gssapi_verify_mech_header(&p
,
733 input_token_buffer
->length
,
737 return (GSS_S_FAILURE
);
739 *buf_len
= input_token_buffer
->length
-
740 (p
- (u_char
*) input_token_buffer
->value
);
742 return (GSS_S_COMPLETE
);
748 free_octet_string(octet_string
*k
)
758 k
->components
= NULL
;
764 * All decoding functions take a pointer `p' to first position in which to
765 * read, from the left, `len' which means the maximum number of characters we
766 * are able to read, `ret' were the value will be returned and `size' where
767 * the number of used bytes is stored. Either 0 or an error code is returned.
771 der_get_unsigned(const unsigned char *p
, size_t len
,
772 unsigned *ret
, size_t *size
)
778 val
= val
* 256 + *p
++;
786 der_get_int(const unsigned char *p
, size_t len
,
787 int *ret
, size_t *size
)
793 val
= (signed char)*p
++;
795 val
= val
* 256 + *p
++;
804 der_get_length(const unsigned char *p
, size_t len
,
805 size_t *val
, size_t *size
)
810 return (ASN1_OVERRUN
);
823 *val
= ASN1_INDEFINITE
;
830 return (ASN1_OVERRUN
);
831 e
= der_get_unsigned(p
, v
, &tmp
, &l
);
842 der_get_octet_string(const unsigned char *p
, size_t len
,
843 octet_string
*data
, size_t *size
)
846 data
->data
= malloc(len
);
847 if (data
->data
== NULL
&& data
->length
!= 0)
849 memcpy(data
->data
, p
, len
);
856 der_get_oid(const unsigned char *p
, size_t len
,
857 oid
*data
, size_t *size
)
863 return (ASN1_OVERRUN
);
865 data
->components
= malloc(len
* sizeof(*data
->components
));
866 if (data
->components
== NULL
&& len
!= 0)
868 data
->components
[0] = (*p
) / 40;
869 data
->components
[1] = (*p
) % 40;
872 for (n
= 2; len
> 0; ++n
) {
877 u
= u
* 128 + (*p
++ % 128);
878 } while (len
> 0 && p
[-1] & 0x80);
879 data
->components
[n
] = u
;
883 return (ASN1_OVERRUN
);
892 der_get_tag(const unsigned char *p
, size_t len
,
893 Der_class
*class, Der_type
*type
,
894 int *tag
, size_t *size
)
897 return (ASN1_OVERRUN
);
898 *class = (Der_class
) (((*p
) >> 6) & 0x03);
899 *type
= (Der_type
) (((*p
) >> 5) & 0x01);
907 der_match_tag(const unsigned char *p
, size_t len
,
908 Der_class
class, Der_type type
,
909 int tag
, size_t *size
)
917 e
= der_get_tag(p
, len
, &thisclass
, &thistype
, &thistag
, &l
);
920 if (class != thisclass
|| type
!= thistype
)
921 return (ASN1_BAD_ID
);
923 return (ASN1_MISPLACED_FIELD
);
925 return (ASN1_MISSING_FIELD
);
932 der_match_tag_and_length(const unsigned char *p
, size_t len
,
933 Der_class
class, Der_type type
, int tag
,
934 size_t *length_ret
, size_t *size
)
939 e
= der_match_tag(p
, len
, class, type
, tag
, &l
);
945 e
= der_get_length(p
, len
, length_ret
, &l
);
957 decode_enumerated(const unsigned char *p
, size_t len
, void *num
, size_t *size
)
963 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_Enumerated
, &l
);
969 e
= der_get_length(p
, len
, &reallen
, &l
);
975 e
= der_get_int(p
, reallen
, num
, &l
);
987 decode_octet_string(const unsigned char *p
, size_t len
,
988 octet_string
*k
, size_t *size
)
995 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_OctetString
, &l
);
1002 e
= der_get_length(p
, len
, &slen
, &l
);
1009 return (ASN1_OVERRUN
);
1011 e
= der_get_octet_string(p
, slen
, k
, &l
);
1023 decode_oid(const unsigned char *p
, size_t len
,
1024 oid
*k
, size_t *size
)
1031 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_OID
, &l
);
1038 e
= der_get_length(p
, len
, &slen
, &l
);
1045 return (ASN1_OVERRUN
);
1047 e
= der_get_oid(p
, slen
, k
, &l
);
1059 fix_dce(size_t reallen
, size_t *len
)
1061 if (reallen
== ASN1_INDEFINITE
)
1072 len_unsigned(unsigned val
)
1084 length_len(size_t len
)
1089 return (len_unsigned(len
) + 1);
1096 * All encoding functions take a pointer `p' to first position in which to
1097 * write, from the right, `len' which means the maximum number of characters
1098 * we are able to write. The function returns the number of characters
1099 * written in `size' (if non-NULL). The return value is 0 or an error.
1103 der_put_unsigned(unsigned char *p
, size_t len
, unsigned val
, size_t *size
)
1105 unsigned char *base
= p
;
1108 while (len
> 0 && val
) {
1114 return (ASN1_OVERFLOW
);
1120 return (ASN1_OVERFLOW
);
1129 der_put_int(unsigned char *p
, size_t len
, int val
, size_t *size
)
1131 unsigned char *base
= p
;
1136 return (ASN1_OVERFLOW
);
1143 return (ASN1_OVERFLOW
);
1151 return (ASN1_OVERFLOW
);
1152 *p
-- = ~(val
% 256);
1158 return (ASN1_OVERFLOW
);
1168 der_put_length(unsigned char *p
, size_t len
, size_t val
, size_t *size
)
1171 return (ASN1_OVERFLOW
);
1180 e
= der_put_unsigned(p
, len
- 1, val
, &l
);
1191 der_put_octet_string(unsigned char *p
, size_t len
,
1192 const octet_string
*data
, size_t *size
)
1194 if (len
< data
->length
)
1195 return (ASN1_OVERFLOW
);
1197 len
-= data
->length
;
1198 memcpy(p
+ 1, data
->data
, data
->length
);
1199 *size
= data
->length
;
1204 der_put_oid(unsigned char *p
, size_t len
,
1205 const oid
*data
, size_t *size
)
1207 unsigned char *base
= p
;
1210 for (n
= data
->length
- 1; n
>= 2; --n
) {
1211 unsigned u
= data
->components
[n
];
1214 return (ASN1_OVERFLOW
);
1220 return (ASN1_OVERFLOW
);
1221 *p
-- = 128 + u
% 128;
1227 return (ASN1_OVERFLOW
);
1228 *p
-- = 40 * data
->components
[0] + data
->components
[1];
1234 der_put_tag(unsigned char *p
, size_t len
, Der_class
class, Der_type type
,
1235 int tag
, size_t *size
)
1238 return (ASN1_OVERFLOW
);
1239 *p
= (class << 6) | (type
<< 5) | tag
; /* XXX */
1245 der_put_length_and_tag(unsigned char *p
, size_t len
, size_t len_val
,
1246 Der_class
class, Der_type type
, int tag
, size_t *size
)
1252 e
= der_put_length(p
, len
, len_val
, &l
);
1258 e
= der_put_tag(p
, len
, class, type
, tag
, &l
);
1269 encode_enumerated(unsigned char *p
, size_t len
, const void *data
, size_t *size
)
1271 unsigned num
= *(const unsigned *)data
;
1276 e
= der_put_int(p
, len
, num
, &l
);
1282 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_Enumerated
, &l
);
1293 encode_octet_string(unsigned char *p
, size_t len
,
1294 const octet_string
*k
, size_t *size
)
1300 e
= der_put_octet_string(p
, len
, k
, &l
);
1306 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_OctetString
, &l
);
1317 encode_oid(unsigned char *p
, size_t len
,
1318 const oid
*k
, size_t *size
)
1324 e
= der_put_oid(p
, len
, k
, &l
);
1330 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_OID
, &l
);
1344 gssapi_encap_length(size_t data_len
,
1351 *len
= 1 + 1 + mech
->length
+ data_len
;
1353 len_len
= length_len(*len
);
1355 *total_len
= 1 + len_len
+ *len
;
1359 gssapi_mech_make_header(u_char
*p
,
1364 size_t len_len
, foo
;
1367 len_len
= length_len(len
);
1368 e
= der_put_length(p
+ len_len
- 1, len_len
, len
, &foo
);
1369 if (e
|| foo
!= len_len
)
1373 *p
++ = mech
->length
;
1374 memcpy(p
, mech
->elements
, mech
->length
);
1380 * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
1384 gssapi_spnego_encapsulate(OM_uint32
* minor_status
,
1387 gss_buffer_t output_token
,
1390 size_t len
, outer_len
;
1393 gssapi_encap_length(buf_size
, &len
, &outer_len
, mech
);
1395 output_token
->length
= outer_len
;
1396 output_token
->value
= malloc(outer_len
);
1397 if (output_token
->value
== NULL
) {
1398 *minor_status
= ENOMEM
;
1399 return (GSS_S_FAILURE
);
1401 p
= gssapi_mech_make_header(output_token
->value
, len
, mech
);
1403 if (output_token
->length
!= 0)
1404 gss_release_buffer(minor_status
, output_token
);
1405 return (GSS_S_FAILURE
);
1407 memcpy(p
, buf
, buf_size
);
1408 return (GSS_S_COMPLETE
);
1411 /* init_sec_context.c */
1413 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
1414 * based on Heimdal code)
1418 add_mech(MechTypeList
* mech_list
, gss_OID mech
)
1423 tmp
= realloc(mech_list
->val
, (mech_list
->len
+ 1) * sizeof(*tmp
));
1426 mech_list
->val
= tmp
;
1428 ret
= der_get_oid(mech
->elements
, mech
->length
,
1429 &mech_list
->val
[mech_list
->len
], NULL
);
1438 * return the length of the mechanism in token or -1
1439 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
1443 gssapi_krb5_get_mech(const u_char
*ptr
,
1445 const u_char
**mech_ret
)
1447 size_t len
, len_len
, mech_len
, foo
;
1448 const u_char
*p
= ptr
;
1455 e
= der_get_length (p
, total_len
- 1, &len
, &len_len
);
1456 if (e
|| 1 + len_len
+ len
!= total_len
)
1461 e
= der_get_length (p
, total_len
- 1 - len_len
- 1,
1471 spnego_initial(OM_uint32
*minor_status
,
1472 const gss_cred_id_t initiator_cred_handle
,
1473 gss_ctx_id_t
*context_handle
,
1474 const gss_name_t target_name
,
1475 const gss_OID mech_type
,
1476 OM_uint32 req_flags
,
1478 const gss_channel_bindings_t input_chan_bindings
,
1479 const gss_buffer_t input_token
,
1480 gss_OID
*actual_mech_type
,
1481 gss_buffer_t output_token
,
1482 OM_uint32
*ret_flags
,
1483 OM_uint32
*time_rec
)
1485 NegTokenInit token_init
;
1486 OM_uint32 major_status
, minor_status2
;
1487 gss_buffer_desc krb5_output_token
= GSS_C_EMPTY_BUFFER
;
1488 unsigned char *buf
= NULL
;
1495 memset(&token_init
, 0, sizeof(token_init
));
1497 ret
= add_mech(&token_init
.mechTypes
, GSS_KRB5_MECH
);
1499 *minor_status
= ret
;
1500 ret
= GSS_S_FAILURE
;
1504 major_status
= gss_init_sec_context(minor_status
,
1505 initiator_cred_handle
,
1511 input_chan_bindings
,
1517 if (GSS_ERROR(major_status
)) {
1521 if (krb5_output_token
.length
> 0) {
1522 token_init
.mechToken
= malloc(sizeof(*token_init
.mechToken
));
1523 if (token_init
.mechToken
== NULL
) {
1524 *minor_status
= ENOMEM
;
1525 ret
= GSS_S_FAILURE
;
1528 token_init
.mechToken
->data
= krb5_output_token
.value
;
1529 token_init
.mechToken
->length
= krb5_output_token
.length
;
1532 * The MS implementation of SPNEGO seems to not like the mechListMIC
1533 * field, so we omit it (it's optional anyway)
1537 buf
= malloc(buf_size
);
1540 ret
= encode_NegTokenInit(buf
+ buf_size
- 1,
1546 ret
= der_put_length_and_tag(buf
+ buf_size
- len
- 1,
1557 if (ret
== ASN1_OVERFLOW
) {
1561 tmp
= realloc(buf
, buf_size
);
1563 *minor_status
= ENOMEM
;
1564 ret
= GSS_S_FAILURE
;
1569 *minor_status
= ret
;
1570 ret
= GSS_S_FAILURE
;
1574 } while (ret
== ASN1_OVERFLOW
);
1576 ret
= gssapi_spnego_encapsulate(minor_status
,
1577 buf
+ buf_size
- len
, len
,
1578 output_token
, GSS_SPNEGO_MECH
);
1579 if (ret
== GSS_S_COMPLETE
)
1583 if (token_init
.mechToken
!= NULL
) {
1584 free(token_init
.mechToken
);
1585 token_init
.mechToken
= NULL
;
1587 free_NegTokenInit(&token_init
);
1588 if (krb5_output_token
.length
!= 0)
1589 gss_release_buffer(&minor_status2
, &krb5_output_token
);
1597 spnego_reply(OM_uint32
*minor_status
,
1598 const gss_cred_id_t initiator_cred_handle
,
1599 gss_ctx_id_t
*context_handle
,
1600 const gss_name_t target_name
,
1601 const gss_OID mech_type
,
1602 OM_uint32 req_flags
,
1604 const gss_channel_bindings_t input_chan_bindings
,
1605 const gss_buffer_t input_token
,
1606 gss_OID
*actual_mech_type
,
1607 gss_buffer_t output_token
,
1608 OM_uint32
*ret_flags
,
1609 OM_uint32
*time_rec
)
1617 gss_buffer_desc sub_token
;
1624 output_token
->length
= 0;
1625 output_token
->value
= NULL
;
1628 * SPNEGO doesn't include gss wrapping on SubsequentContextToken
1629 * like the Kerberos 5 mech does. But lets check for it anyway.
1632 mech_len
= gssapi_krb5_get_mech(input_token
->value
,
1633 input_token
->length
,
1637 buf
= input_token
->value
;
1638 buf_size
= input_token
->length
;
1639 } else if ((size_t)mech_len
== GSS_KRB5_MECH
->length
&&
1640 memcmp(GSS_KRB5_MECH
->elements
, p
, mech_len
) == 0)
1641 return (gss_init_sec_context(minor_status
,
1642 initiator_cred_handle
,
1648 input_chan_bindings
,
1654 else if ((size_t)mech_len
== GSS_SPNEGO_MECH
->length
&&
1655 memcmp(GSS_SPNEGO_MECH
->elements
, p
, mech_len
) == 0) {
1656 ret
= gssapi_spnego_decapsulate(minor_status
,
1664 return (GSS_S_BAD_MECH
);
1666 ret
= der_match_tag_and_length(buf
, buf_size
,
1667 ASN1_C_CONTEXT
, CONS
, 1, &len
, &taglen
);
1671 if(len
> buf_size
- taglen
)
1672 return (ASN1_OVERRUN
);
1674 ret
= decode_NegTokenResp(buf
+ taglen
, len
, &resp
, NULL
);
1676 *minor_status
= ENOMEM
;
1677 return (GSS_S_FAILURE
);
1680 if (resp
.negState
== NULL
||
1681 *(resp
.negState
) == reject
||
1682 resp
.supportedMech
== NULL
) {
1683 free_NegTokenResp(&resp
);
1684 return (GSS_S_BAD_MECH
);
1687 ret
= der_put_oid(oidbuf
+ sizeof(oidbuf
) - 1,
1691 if (ret
|| oidlen
!= GSS_KRB5_MECH
->length
||
1692 memcmp(oidbuf
+ sizeof(oidbuf
) - oidlen
,
1693 GSS_KRB5_MECH
->elements
,
1695 free_NegTokenResp(&resp
);
1696 return GSS_S_BAD_MECH
;
1699 if (resp
.responseToken
!= NULL
) {
1700 sub_token
.length
= resp
.responseToken
->length
;
1701 sub_token
.value
= resp
.responseToken
->data
;
1703 sub_token
.length
= 0;
1704 sub_token
.value
= NULL
;
1707 ret
= gss_init_sec_context(minor_status
,
1708 initiator_cred_handle
,
1714 input_chan_bindings
,
1721 free_NegTokenResp(&resp
);
1726 * XXXSRA I don't think this limited implementation ever needs
1727 * to check the MIC -- our preferred mechanism (Kerberos)
1728 * authenticates its own messages and is the only mechanism
1729 * we'll accept, so if the mechanism negotiation completes
1730 * successfully, we don't need the MIC. See RFC 4178.
1733 free_NegTokenResp(&resp
);
1740 gss_init_sec_context_spnego(OM_uint32
*minor_status
,
1741 const gss_cred_id_t initiator_cred_handle
,
1742 gss_ctx_id_t
*context_handle
,
1743 const gss_name_t target_name
,
1744 const gss_OID mech_type
,
1745 OM_uint32 req_flags
,
1747 const gss_channel_bindings_t input_chan_bindings
,
1748 const gss_buffer_t input_token
,
1749 gss_OID
*actual_mech_type
,
1750 gss_buffer_t output_token
,
1751 OM_uint32
*ret_flags
,
1752 OM_uint32
*time_rec
)
1754 /* Dirty trick to suppress compiler warnings */
1756 /* Figure out whether we're starting over or processing a reply */
1758 if (input_token
== GSS_C_NO_BUFFER
|| input_token
->length
== 0)
1759 return (spnego_initial(minor_status
,
1760 initiator_cred_handle
,
1766 input_chan_bindings
,
1773 return (spnego_reply(minor_status
,
1774 initiator_cred_handle
,
1780 input_chan_bindings
,