4 * Copyright (C) 2006-2009 Internet Systems Consortium, Inc. ("ISC")
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.
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.
19 /* Id: spnego.c,v 1.12 2009/07/21 06:53:09 marka Exp */
23 * Portable SPNEGO implementation.
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
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)
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).
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.
51 * Portions of this code were derived from mod_auth_kerb and Heimdal.
52 * These packages are available from:
54 * http://modauthkerb.sourceforge.net/
55 * http://www.pdc.kth.se/heimdal/
57 * and were released under the following licenses:
59 * ----------------------------------------------------------------
61 * Copyright (c) 2004 Masarykova universita
62 * (Masaryk University, Brno, Czech Republic)
63 * All rights reserved.
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions are met:
68 * 1. Redistributions of source code must retain the above copyright notice,
69 * this list of conditions and the following disclaimer.
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.
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.
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.
91 * ----------------------------------------------------------------
93 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
94 * (Royal Institute of Technology, Stockholm, Sweden).
95 * All rights reserved.
97 * Redistribution and use in source and binary forms, with or without
98 * modification, are permitted provided that the following conditions
101 * 1. Redistributions of source code must retain the above copyright
102 * notice, this list of conditions and the following disclaimer.
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.
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.
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
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.
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.
144 #include <isc/buffer.h>
146 #include <isc/entropy.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>
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>
164 #include <dst/gssapi.h>
165 #include <dst/result.h>
167 #include "dst_internal.h"
175 /* Generated from ../../../lib/asn1/asn1_err.et */
177 typedef enum asn1_error_number
{
178 ASN1_BAD_TIMEFORMAT
= 1859794432,
179 ASN1_MISSING_FIELD
= 1859794433,
180 ASN1_MISPLACED_FIELD
= 1859794434,
181 ASN1_TYPE_MISMATCH
= 1859794435,
182 ASN1_OVERFLOW
= 1859794436,
183 ASN1_OVERRUN
= 1859794437,
184 ASN1_BAD_ID
= 1859794438,
185 ASN1_BAD_LENGTH
= 1859794439,
186 ASN1_BAD_FORMAT
= 1859794440,
187 ASN1_PARSE_ERROR
= 1859794441
190 #define ERROR_TABLE_BASE_asn1 1859794432
192 #define __asn1_common_definitions__
194 typedef struct octet_string
{
199 typedef char *general_string
;
201 typedef char *utf8_string
;
205 unsigned *components
;
211 ASN1_C_UNIV
= 0, ASN1_C_APPL
= 1,
212 ASN1_C_CONTEXT
= 2, ASN1_C_PRIVATE
= 3
231 UT_PrintableString
= 19,
234 UT_GeneralizedTime
= 24,
235 UT_VisibleString
= 26,
236 UT_GeneralString
= 27
239 #define ASN1_INDEFINITE 0xdce0deed
242 der_get_length(const unsigned char *p
, size_t len
,
243 size_t * val
, size_t * size
);
246 der_get_octet_string(const unsigned char *p
, size_t len
,
247 octet_string
* data
, size_t * size
);
249 der_get_oid(const unsigned char *p
, size_t len
,
250 oid
* data
, size_t * size
);
252 der_get_tag(const unsigned char *p
, size_t len
,
253 Der_class
* class, Der_type
* type
,
254 int *tag
, size_t * size
);
257 der_match_tag(const unsigned char *p
, size_t len
,
258 Der_class
class, Der_type type
,
259 int tag
, size_t * size
);
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
);
266 decode_oid(const unsigned char *p
, size_t len
,
267 oid
* k
, size_t * size
);
270 decode_enumerated(const unsigned char *p
, size_t len
, void *num
, size_t *size
);
273 decode_octet_string(const unsigned char *, size_t, octet_string
*, size_t *);
276 der_put_int(unsigned char *p
, size_t len
, int val
, size_t *);
279 der_put_length(unsigned char *p
, size_t len
, size_t val
, size_t *);
282 der_put_octet_string(unsigned char *p
, size_t len
,
283 const octet_string
* data
, size_t *);
285 der_put_oid(unsigned char *p
, size_t len
,
286 const oid
* data
, size_t * size
);
288 der_put_tag(unsigned char *p
, size_t len
, Der_class
class, Der_type type
,
291 der_put_length_and_tag(unsigned char *, size_t, size_t,
292 Der_class
, Der_type
, int, size_t *);
295 encode_enumerated(unsigned char *p
, size_t len
, const void *data
, size_t *);
298 encode_octet_string(unsigned char *p
, size_t len
,
299 const octet_string
* k
, size_t *);
301 encode_oid(unsigned char *p
, size_t len
,
302 const oid
* k
, size_t *);
305 free_octet_string(octet_string
* k
);
311 length_len(size_t len
);
314 fix_dce(size_t reallen
, size_t * len
);
317 * Include stuff generated by the ASN.1 compiler.
320 #include "spnego_asn1.c"
322 static unsigned char gss_krb5_mech_oid_bytes
[] = {
323 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
326 static gss_OID_desc gss_krb5_mech_oid_desc
= {
327 sizeof(gss_krb5_mech_oid_bytes
),
328 gss_krb5_mech_oid_bytes
331 static gss_OID GSS_KRB5_MECH
= &gss_krb5_mech_oid_desc
;
333 static unsigned char gss_mskrb5_mech_oid_bytes
[] = {
334 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
337 static gss_OID_desc gss_mskrb5_mech_oid_desc
= {
338 sizeof(gss_mskrb5_mech_oid_bytes
),
339 gss_mskrb5_mech_oid_bytes
342 static gss_OID GSS_MSKRB5_MECH
= &gss_mskrb5_mech_oid_desc
;
344 static unsigned char gss_spnego_mech_oid_bytes
[] = {
345 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
348 static gss_OID_desc gss_spnego_mech_oid_desc
= {
349 sizeof(gss_spnego_mech_oid_bytes
),
350 gss_spnego_mech_oid_bytes
353 static gss_OID GSS_SPNEGO_MECH
= &gss_spnego_mech_oid_desc
;
355 /* spnegokrb5_locl.h */
358 gssapi_spnego_encapsulate(OM_uint32
*,
365 gssapi_spnego_decapsulate(OM_uint32
*,
371 /* mod_auth_kerb.c */
374 cmp_gss_type(gss_buffer_t token
, gss_OID oid
)
379 if (token
->length
== 0)
380 return (GSS_S_DEFECTIVE_TOKEN
);
384 return (GSS_S_DEFECTIVE_TOKEN
);
387 if ((len
& 0x7f) > 4)
388 return (GSS_S_DEFECTIVE_TOKEN
);
392 return (GSS_S_DEFECTIVE_TOKEN
);
394 if (((OM_uint32
) *p
++) != oid
->length
)
395 return (GSS_S_DEFECTIVE_TOKEN
);
397 return (memcmp(p
, oid
->elements
, oid
->length
));
400 /* accept_sec_context.c */
402 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
403 * based on Heimdal code)
407 code_NegTokenArg(OM_uint32
* minor_status
,
408 const NegTokenResp
* resp
,
409 unsigned char **outbuf
,
410 size_t * outbuf_size
)
414 size_t buf_size
, buf_len
;
417 buf
= malloc(buf_size
);
419 *minor_status
= ENOMEM
;
420 return (GSS_S_FAILURE
);
423 ret
= encode_NegTokenResp(buf
+ buf_size
- 1,
429 ret
= der_put_length_and_tag(buf
+ buf_size
- buf_len
- 1,
440 if (ret
== ASN1_OVERFLOW
) {
444 tmp
= realloc(buf
, buf_size
);
446 *minor_status
= ENOMEM
;
448 return (GSS_S_FAILURE
);
454 return (GSS_S_FAILURE
);
457 } while (ret
== ASN1_OVERFLOW
);
459 *outbuf
= malloc(buf_len
);
460 if (*outbuf
== NULL
) {
461 *minor_status
= ENOMEM
;
463 return (GSS_S_FAILURE
);
465 memcpy(*outbuf
, buf
+ buf_size
- buf_len
, buf_len
);
466 *outbuf_size
= buf_len
;
470 return (GSS_S_COMPLETE
);
474 send_reject(OM_uint32
* minor_status
,
475 gss_buffer_t output_token
)
480 resp
.negState
= malloc(sizeof(*resp
.negState
));
481 if (resp
.negState
== NULL
) {
482 *minor_status
= ENOMEM
;
483 return (GSS_S_FAILURE
);
485 *(resp
.negState
) = reject
;
487 resp
.supportedMech
= NULL
;
488 resp
.responseToken
= NULL
;
489 resp
.mechListMIC
= NULL
;
491 ret
= code_NegTokenArg(minor_status
, &resp
,
492 (unsigned char **)&output_token
->value
,
493 &output_token
->length
);
494 free_NegTokenResp(&resp
);
498 return (GSS_S_BAD_MECH
);
502 send_accept(OM_uint32
* minor_status
,
503 gss_buffer_t output_token
,
504 gss_buffer_t mech_token
,
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
);
516 *(resp
.negState
) = accept_completed
;
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
);
524 ret
= der_get_oid(pref
->elements
,
529 free_NegTokenResp(&resp
);
530 *minor_status
= ENOMEM
;
531 return (GSS_S_FAILURE
);
533 if (mech_token
!= NULL
&& mech_token
->length
!= 0) {
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
);
540 resp
.responseToken
->length
= mech_token
->length
;
541 resp
.responseToken
->data
= mech_token
->value
;
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
;
551 free_NegTokenResp(&resp
);
555 return (GSS_S_COMPLETE
);
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
,
566 gss_buffer_t output_token
,
567 OM_uint32
*ret_flags
,
569 gss_cred_id_t
*delegated_cred_handle
)
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
;
579 size_t len
, taglen
, ni_len
;
585 * Before doing anything else, see whether this is a SPNEGO
586 * PDU. If not, dispatch to the GSSAPI library and get out.
589 if (cmp_gss_type(input_token_buffer
, GSS_SPNEGO_MECH
))
590 return (gss_accept_sec_context(minor_status
,
592 acceptor_cred_handle
,
600 delegated_cred_handle
));
603 * If we get here, it's SPNEGO.
606 memset(&init_token
, 0, sizeof(init_token
));
608 ret
= gssapi_spnego_decapsulate(minor_status
, input_token_buffer
,
609 &buf
, &buf_size
, GSS_SPNEGO_MECH
);
613 ret
= der_match_tag_and_length(buf
, buf_size
, ASN1_C_CONTEXT
, CONS
,
618 ret
= decode_NegTokenInit(buf
+ taglen
, len
, &init_token
, &ni_len
);
620 *minor_status
= EINVAL
; /* XXX */
621 return (GSS_S_DEFECTIVE_TOKEN
);
624 for (i
= 0; !found
&& i
< init_token
.mechTypes
.len
; ++i
) {
625 unsigned char mechbuf
[17];
628 ret
= der_put_oid(mechbuf
+ sizeof(mechbuf
) - 1,
630 &init_token
.mechTypes
.val
[i
],
633 return (GSS_S_DEFECTIVE_TOKEN
);
634 if (mech_len
== GSS_KRB5_MECH
->length
&&
635 memcmp(GSS_KRB5_MECH
->elements
,
636 mechbuf
+ sizeof(mechbuf
) - mech_len
,
641 if (mech_len
== GSS_MSKRB5_MECH
->length
&&
642 memcmp(GSS_MSKRB5_MECH
->elements
,
643 mechbuf
+ sizeof(mechbuf
) - mech_len
,
647 pref
= GSS_MSKRB5_MECH
;
653 return (send_reject(minor_status
, output_token
));
655 if (i
== 0 && init_token
.mechToken
!= NULL
) {
656 ibuf
.length
= init_token
.mechToken
->length
;
657 ibuf
.value
= init_token
.mechToken
->data
;
659 major_status
= gss_accept_sec_context(minor_status
,
661 acceptor_cred_handle
,
669 delegated_cred_handle
);
670 if (GSS_ERROR(major_status
)) {
671 send_reject(&minor_status2
, output_token
);
672 return (major_status
);
676 ret
= send_accept(&minor_status2
, output_token
, ot
, pref
);
677 if (ot
!= NULL
&& ot
->length
!= 0)
678 gss_release_buffer(&minor_status2
, ot
);
686 gssapi_verify_mech_header(u_char
** str
,
690 size_t len
, len_len
, mech_len
, foo
;
695 return (GSS_S_DEFECTIVE_TOKEN
);
697 return (GSS_S_DEFECTIVE_TOKEN
);
698 e
= der_get_length(p
, total_len
- 1, &len
, &len_len
);
699 if (e
|| 1 + len_len
+ len
!= total_len
)
700 return (GSS_S_DEFECTIVE_TOKEN
);
703 return (GSS_S_DEFECTIVE_TOKEN
);
704 e
= der_get_length(p
, total_len
- 1 - len_len
- 1,
707 return (GSS_S_DEFECTIVE_TOKEN
);
709 if (mech_len
!= mech
->length
)
710 return (GSS_S_BAD_MECH
);
711 if (memcmp(p
, mech
->elements
, mech
->length
) != 0)
712 return (GSS_S_BAD_MECH
);
715 return (GSS_S_COMPLETE
);
719 * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
720 * not copy data, so just free `in_token'.
724 gssapi_spnego_decapsulate(OM_uint32
*minor_status
,
725 gss_buffer_t input_token_buffer
,
733 p
= input_token_buffer
->value
;
734 ret
= gssapi_verify_mech_header(&p
,
735 input_token_buffer
->length
,
739 return (GSS_S_FAILURE
);
741 *buf_len
= input_token_buffer
->length
-
742 (p
- (u_char
*) input_token_buffer
->value
);
744 return (GSS_S_COMPLETE
);
750 free_octet_string(octet_string
*k
)
760 k
->components
= NULL
;
766 * All decoding functions take a pointer `p' to first position in which to
767 * read, from the left, `len' which means the maximum number of characters we
768 * are able to read, `ret' were the value will be returned and `size' where
769 * the number of used bytes is stored. Either 0 or an error code is returned.
773 der_get_unsigned(const unsigned char *p
, size_t len
,
774 unsigned *ret
, size_t *size
)
780 val
= val
* 256 + *p
++;
788 der_get_int(const unsigned char *p
, size_t len
,
789 int *ret
, size_t *size
)
795 val
= (signed char)*p
++;
797 val
= val
* 256 + *p
++;
806 der_get_length(const unsigned char *p
, size_t len
,
807 size_t *val
, size_t *size
)
812 return (ASN1_OVERRUN
);
825 *val
= ASN1_INDEFINITE
;
832 return (ASN1_OVERRUN
);
833 e
= der_get_unsigned(p
, v
, &tmp
, &l
);
844 der_get_octet_string(const unsigned char *p
, size_t len
,
845 octet_string
*data
, size_t *size
)
848 data
->data
= malloc(len
);
849 if (data
->data
== NULL
&& data
->length
!= 0)
851 memcpy(data
->data
, p
, len
);
858 der_get_oid(const unsigned char *p
, size_t len
,
859 oid
*data
, size_t *size
)
865 return (ASN1_OVERRUN
);
867 data
->components
= malloc(len
* sizeof(*data
->components
));
868 if (data
->components
== NULL
&& len
!= 0)
870 data
->components
[0] = (*p
) / 40;
871 data
->components
[1] = (*p
) % 40;
874 for (n
= 2; len
> 0; ++n
) {
879 u
= u
* 128 + (*p
++ % 128);
880 } while (len
> 0 && p
[-1] & 0x80);
881 data
->components
[n
] = u
;
885 return (ASN1_OVERRUN
);
894 der_get_tag(const unsigned char *p
, size_t len
,
895 Der_class
*class, Der_type
*type
,
896 int *tag
, size_t *size
)
899 return (ASN1_OVERRUN
);
900 *class = (Der_class
) (((*p
) >> 6) & 0x03);
901 *type
= (Der_type
) (((*p
) >> 5) & 0x01);
909 der_match_tag(const unsigned char *p
, size_t len
,
910 Der_class
class, Der_type type
,
911 int tag
, size_t *size
)
919 e
= der_get_tag(p
, len
, &thisclass
, &thistype
, &thistag
, &l
);
922 if (class != thisclass
|| type
!= thistype
)
923 return (ASN1_BAD_ID
);
925 return (ASN1_MISPLACED_FIELD
);
927 return (ASN1_MISSING_FIELD
);
934 der_match_tag_and_length(const unsigned char *p
, size_t len
,
935 Der_class
class, Der_type type
, int tag
,
936 size_t *length_ret
, size_t *size
)
941 e
= der_match_tag(p
, len
, class, type
, tag
, &l
);
947 e
= der_get_length(p
, len
, length_ret
, &l
);
959 decode_enumerated(const unsigned char *p
, size_t len
, void *num
, size_t *size
)
965 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_Enumerated
, &l
);
971 e
= der_get_length(p
, len
, &reallen
, &l
);
977 e
= der_get_int(p
, reallen
, num
, &l
);
989 decode_octet_string(const unsigned char *p
, size_t len
,
990 octet_string
*k
, size_t *size
)
997 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_OctetString
, &l
);
1004 e
= der_get_length(p
, len
, &slen
, &l
);
1011 return (ASN1_OVERRUN
);
1013 e
= der_get_octet_string(p
, slen
, k
, &l
);
1025 decode_oid(const unsigned char *p
, size_t len
,
1026 oid
*k
, size_t *size
)
1033 e
= der_match_tag(p
, len
, ASN1_C_UNIV
, PRIM
, UT_OID
, &l
);
1040 e
= der_get_length(p
, len
, &slen
, &l
);
1047 return (ASN1_OVERRUN
);
1049 e
= der_get_oid(p
, slen
, k
, &l
);
1061 fix_dce(size_t reallen
, size_t *len
)
1063 if (reallen
== ASN1_INDEFINITE
)
1074 len_unsigned(unsigned val
)
1086 length_len(size_t len
)
1091 return (len_unsigned(len
) + 1);
1098 * All encoding functions take a pointer `p' to first position in which to
1099 * write, from the right, `len' which means the maximum number of characters
1100 * we are able to write. The function returns the number of characters
1101 * written in `size' (if non-NULL). The return value is 0 or an error.
1105 der_put_unsigned(unsigned char *p
, size_t len
, unsigned val
, size_t *size
)
1107 unsigned char *base
= p
;
1110 while (len
> 0 && val
) {
1116 return (ASN1_OVERFLOW
);
1122 return (ASN1_OVERFLOW
);
1131 der_put_int(unsigned char *p
, size_t len
, int val
, size_t *size
)
1133 unsigned char *base
= p
;
1138 return (ASN1_OVERFLOW
);
1145 return (ASN1_OVERFLOW
);
1153 return (ASN1_OVERFLOW
);
1154 *p
-- = ~(val
% 256);
1160 return (ASN1_OVERFLOW
);
1170 der_put_length(unsigned char *p
, size_t len
, size_t val
, size_t *size
)
1173 return (ASN1_OVERFLOW
);
1182 e
= der_put_unsigned(p
, len
- 1, val
, &l
);
1193 der_put_octet_string(unsigned char *p
, size_t len
,
1194 const octet_string
*data
, size_t *size
)
1196 if (len
< data
->length
)
1197 return (ASN1_OVERFLOW
);
1199 len
-= data
->length
;
1200 memcpy(p
+ 1, data
->data
, data
->length
);
1201 *size
= data
->length
;
1206 der_put_oid(unsigned char *p
, size_t len
,
1207 const oid
*data
, size_t *size
)
1209 unsigned char *base
= p
;
1212 for (n
= data
->length
- 1; n
>= 2; --n
) {
1213 unsigned u
= data
->components
[n
];
1216 return (ASN1_OVERFLOW
);
1222 return (ASN1_OVERFLOW
);
1223 *p
-- = 128 + u
% 128;
1229 return (ASN1_OVERFLOW
);
1230 *p
-- = 40 * data
->components
[0] + data
->components
[1];
1236 der_put_tag(unsigned char *p
, size_t len
, Der_class
class, Der_type type
,
1237 int tag
, size_t *size
)
1240 return (ASN1_OVERFLOW
);
1241 *p
= (class << 6) | (type
<< 5) | tag
; /* XXX */
1247 der_put_length_and_tag(unsigned char *p
, size_t len
, size_t len_val
,
1248 Der_class
class, Der_type type
, int tag
, size_t *size
)
1254 e
= der_put_length(p
, len
, len_val
, &l
);
1260 e
= der_put_tag(p
, len
, class, type
, tag
, &l
);
1271 encode_enumerated(unsigned char *p
, size_t len
, const void *data
, size_t *size
)
1273 unsigned num
= *(const unsigned *)data
;
1278 e
= der_put_int(p
, len
, num
, &l
);
1284 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_Enumerated
, &l
);
1295 encode_octet_string(unsigned char *p
, size_t len
,
1296 const octet_string
*k
, size_t *size
)
1302 e
= der_put_octet_string(p
, len
, k
, &l
);
1308 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_OctetString
, &l
);
1319 encode_oid(unsigned char *p
, size_t len
,
1320 const oid
*k
, size_t *size
)
1326 e
= der_put_oid(p
, len
, k
, &l
);
1332 e
= der_put_length_and_tag(p
, len
, l
, ASN1_C_UNIV
, PRIM
, UT_OID
, &l
);
1346 gssapi_encap_length(size_t data_len
,
1353 *len
= 1 + 1 + mech
->length
+ data_len
;
1355 len_len
= length_len(*len
);
1357 *total_len
= 1 + len_len
+ *len
;
1361 gssapi_mech_make_header(u_char
*p
,
1366 size_t len_len
, foo
;
1369 len_len
= length_len(len
);
1370 e
= der_put_length(p
+ len_len
- 1, len_len
, len
, &foo
);
1371 if (e
|| foo
!= len_len
)
1375 *p
++ = mech
->length
;
1376 memcpy(p
, mech
->elements
, mech
->length
);
1382 * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
1386 gssapi_spnego_encapsulate(OM_uint32
* minor_status
,
1389 gss_buffer_t output_token
,
1392 size_t len
, outer_len
;
1395 gssapi_encap_length(buf_size
, &len
, &outer_len
, mech
);
1397 output_token
->length
= outer_len
;
1398 output_token
->value
= malloc(outer_len
);
1399 if (output_token
->value
== NULL
) {
1400 *minor_status
= ENOMEM
;
1401 return (GSS_S_FAILURE
);
1403 p
= gssapi_mech_make_header(output_token
->value
, len
, mech
);
1405 if (output_token
->length
!= 0)
1406 gss_release_buffer(minor_status
, output_token
);
1407 return (GSS_S_FAILURE
);
1409 memcpy(p
, buf
, buf_size
);
1410 return (GSS_S_COMPLETE
);
1413 /* init_sec_context.c */
1415 * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
1416 * based on Heimdal code)
1420 add_mech(MechTypeList
* mech_list
, gss_OID mech
)
1425 tmp
= realloc(mech_list
->val
, (mech_list
->len
+ 1) * sizeof(*tmp
));
1428 mech_list
->val
= tmp
;
1430 ret
= der_get_oid(mech
->elements
, mech
->length
,
1431 &mech_list
->val
[mech_list
->len
], NULL
);
1440 * return the length of the mechanism in token or -1
1441 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
1445 gssapi_krb5_get_mech(const u_char
*ptr
,
1447 const u_char
**mech_ret
)
1449 size_t len
, len_len
, mech_len
, foo
;
1450 const u_char
*p
= ptr
;
1457 e
= der_get_length (p
, total_len
- 1, &len
, &len_len
);
1458 if (e
|| 1 + len_len
+ len
!= total_len
)
1463 e
= der_get_length (p
, total_len
- 1 - len_len
- 1,
1473 spnego_initial(OM_uint32
*minor_status
,
1474 const gss_cred_id_t initiator_cred_handle
,
1475 gss_ctx_id_t
*context_handle
,
1476 const gss_name_t target_name
,
1477 const gss_OID mech_type
,
1478 OM_uint32 req_flags
,
1480 const gss_channel_bindings_t input_chan_bindings
,
1481 const gss_buffer_t input_token
,
1482 gss_OID
*actual_mech_type
,
1483 gss_buffer_t output_token
,
1484 OM_uint32
*ret_flags
,
1485 OM_uint32
*time_rec
)
1487 NegTokenInit token_init
;
1488 OM_uint32 major_status
, minor_status2
;
1489 gss_buffer_desc krb5_output_token
= GSS_C_EMPTY_BUFFER
;
1490 unsigned char *buf
= NULL
;
1497 memset(&token_init
, 0, sizeof(token_init
));
1499 ret
= add_mech(&token_init
.mechTypes
, GSS_KRB5_MECH
);
1501 *minor_status
= ret
;
1502 ret
= GSS_S_FAILURE
;
1506 major_status
= gss_init_sec_context(minor_status
,
1507 initiator_cred_handle
,
1513 input_chan_bindings
,
1519 if (GSS_ERROR(major_status
)) {
1523 if (krb5_output_token
.length
> 0) {
1524 token_init
.mechToken
= malloc(sizeof(*token_init
.mechToken
));
1525 if (token_init
.mechToken
== NULL
) {
1526 *minor_status
= ENOMEM
;
1527 ret
= GSS_S_FAILURE
;
1530 token_init
.mechToken
->data
= krb5_output_token
.value
;
1531 token_init
.mechToken
->length
= krb5_output_token
.length
;
1534 * The MS implementation of SPNEGO seems to not like the mechListMIC
1535 * field, so we omit it (it's optional anyway)
1539 buf
= malloc(buf_size
);
1542 ret
= encode_NegTokenInit(buf
+ buf_size
- 1,
1548 ret
= der_put_length_and_tag(buf
+ buf_size
- len
- 1,
1559 if (ret
== ASN1_OVERFLOW
) {
1563 tmp
= realloc(buf
, buf_size
);
1565 *minor_status
= ENOMEM
;
1566 ret
= GSS_S_FAILURE
;
1571 *minor_status
= ret
;
1572 ret
= GSS_S_FAILURE
;
1576 } while (ret
== ASN1_OVERFLOW
);
1578 ret
= gssapi_spnego_encapsulate(minor_status
,
1579 buf
+ buf_size
- len
, len
,
1580 output_token
, GSS_SPNEGO_MECH
);
1581 if (ret
== GSS_S_COMPLETE
)
1585 if (token_init
.mechToken
!= NULL
) {
1586 free(token_init
.mechToken
);
1587 token_init
.mechToken
= NULL
;
1589 free_NegTokenInit(&token_init
);
1590 if (krb5_output_token
.length
!= 0)
1591 gss_release_buffer(&minor_status2
, &krb5_output_token
);
1599 spnego_reply(OM_uint32
*minor_status
,
1600 const gss_cred_id_t initiator_cred_handle
,
1601 gss_ctx_id_t
*context_handle
,
1602 const gss_name_t target_name
,
1603 const gss_OID mech_type
,
1604 OM_uint32 req_flags
,
1606 const gss_channel_bindings_t input_chan_bindings
,
1607 const gss_buffer_t input_token
,
1608 gss_OID
*actual_mech_type
,
1609 gss_buffer_t output_token
,
1610 OM_uint32
*ret_flags
,
1611 OM_uint32
*time_rec
)
1619 gss_buffer_desc sub_token
;
1626 output_token
->length
= 0;
1627 output_token
->value
= NULL
;
1630 * SPNEGO doesn't include gss wrapping on SubsequentContextToken
1631 * like the Kerberos 5 mech does. But lets check for it anyway.
1634 mech_len
= gssapi_krb5_get_mech(input_token
->value
,
1635 input_token
->length
,
1639 buf
= input_token
->value
;
1640 buf_size
= input_token
->length
;
1641 } else if ((size_t)mech_len
== GSS_KRB5_MECH
->length
&&
1642 memcmp(GSS_KRB5_MECH
->elements
, p
, mech_len
) == 0)
1643 return (gss_init_sec_context(minor_status
,
1644 initiator_cred_handle
,
1650 input_chan_bindings
,
1656 else if ((size_t)mech_len
== GSS_SPNEGO_MECH
->length
&&
1657 memcmp(GSS_SPNEGO_MECH
->elements
, p
, mech_len
) == 0) {
1658 ret
= gssapi_spnego_decapsulate(minor_status
,
1666 return (GSS_S_BAD_MECH
);
1668 ret
= der_match_tag_and_length(buf
, buf_size
,
1669 ASN1_C_CONTEXT
, CONS
, 1, &len
, &taglen
);
1673 if(len
> buf_size
- taglen
)
1674 return (ASN1_OVERRUN
);
1676 ret
= decode_NegTokenResp(buf
+ taglen
, len
, &resp
, NULL
);
1678 *minor_status
= ENOMEM
;
1679 return (GSS_S_FAILURE
);
1682 if (resp
.negState
== NULL
||
1683 *(resp
.negState
) == reject
||
1684 resp
.supportedMech
== NULL
) {
1685 free_NegTokenResp(&resp
);
1686 return (GSS_S_BAD_MECH
);
1689 ret
= der_put_oid(oidbuf
+ sizeof(oidbuf
) - 1,
1693 if (ret
|| oidlen
!= GSS_KRB5_MECH
->length
||
1694 memcmp(oidbuf
+ sizeof(oidbuf
) - oidlen
,
1695 GSS_KRB5_MECH
->elements
,
1697 free_NegTokenResp(&resp
);
1698 return GSS_S_BAD_MECH
;
1701 if (resp
.responseToken
!= NULL
) {
1702 sub_token
.length
= resp
.responseToken
->length
;
1703 sub_token
.value
= resp
.responseToken
->data
;
1705 sub_token
.length
= 0;
1706 sub_token
.value
= NULL
;
1709 ret
= gss_init_sec_context(minor_status
,
1710 initiator_cred_handle
,
1716 input_chan_bindings
,
1723 free_NegTokenResp(&resp
);
1728 * XXXSRA I don't think this limited implementation ever needs
1729 * to check the MIC -- our preferred mechanism (Kerberos)
1730 * authenticates its own messages and is the only mechanism
1731 * we'll accept, so if the mechanism negotiation completes
1732 * successfully, we don't need the MIC. See RFC 4178.
1735 free_NegTokenResp(&resp
);
1742 gss_init_sec_context_spnego(OM_uint32
*minor_status
,
1743 const gss_cred_id_t initiator_cred_handle
,
1744 gss_ctx_id_t
*context_handle
,
1745 const gss_name_t target_name
,
1746 const gss_OID mech_type
,
1747 OM_uint32 req_flags
,
1749 const gss_channel_bindings_t input_chan_bindings
,
1750 const gss_buffer_t input_token
,
1751 gss_OID
*actual_mech_type
,
1752 gss_buffer_t output_token
,
1753 OM_uint32
*ret_flags
,
1754 OM_uint32
*time_rec
)
1756 /* Dirty trick to suppress compiler warnings */
1758 /* Figure out whether we're starting over or processing a reply */
1760 if (input_token
== GSS_C_NO_BUFFER
|| input_token
->length
== 0)
1761 return (spnego_initial(minor_status
,
1762 initiator_cred_handle
,
1768 input_chan_bindings
,
1775 return (spnego_reply(minor_status
,
1776 initiator_cred_handle
,
1782 input_chan_bindings
,