"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/spnego.c" (7 Sep 2020, 41143 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spnego.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.11.22_vs_9.11.23.

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