spnego.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2015  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id$ */
00018 
00019 /*! \file
00020  * \brief
00021  * Portable SPNEGO implementation.
00022  *
00023  * This is part of a portable implementation of the SPNEGO protocol
00024  * (RFCs 2478 and 4178).  This implementation uses the RFC 4178 ASN.1
00025  * module but is not a full implementation of the RFC 4178 protocol;
00026  * at the moment, we only support GSS-TSIG with Kerberos
00027  * authentication, so we only need enough of the SPNEGO protocol to
00028  * support that.
00029  *
00030  * The files that make up this portable SPNEGO implementation are:
00031  * \li  spnego.c        (this file)
00032  * \li  spnego.h        (API SPNEGO exports to the rest of lib/dns)
00033  * \li  spnego.asn1     (SPNEGO ASN.1 module)
00034  * \li  spnego_asn1.c   (routines generated from spngo.asn1)
00035  * \li  spnego_asn1.pl  (perl script to generate spnego_asn1.c)
00036  *
00037  * Everything but the functions exported in spnego.h is static, to
00038  * avoid possible conflicts with other libraries (particularly Heimdal,
00039  * since much of this code comes from Heimdal by way of mod_auth_kerb).
00040  *
00041  * spnego_asn1.c is shipped as part of lib/dns because generating it
00042  * requires both Perl and the Heimdal ASN.1 compiler.  See
00043  * spnego_asn1.pl for further details.  We've tried to eliminate all
00044  * compiler warnings from the generated code, but you may see a few
00045  * when using a compiler version we haven't tested yet.
00046  */
00047 
00048 /*
00049  * Portions of this code were derived from mod_auth_kerb and Heimdal.
00050  * These packages are available from:
00051  *
00052  *   http://modauthkerb.sourceforge.net/
00053  *   http://www.pdc.kth.se/heimdal/
00054  *
00055  * and were released under the following licenses:
00056  *
00057  * ----------------------------------------------------------------
00058  *
00059  * Copyright (c) 2004 Masarykova universita
00060  * (Masaryk University, Brno, Czech Republic)
00061  * All rights reserved.
00062  *
00063  * Redistribution and use in source and binary forms, with or without
00064  * modification, are permitted provided that the following conditions are met:
00065  *
00066  * 1. Redistributions of source code must retain the above copyright notice,
00067  *    this list of conditions and the following disclaimer.
00068  *
00069  * 2. Redistributions in binary form must reproduce the above copyright
00070  *    notice, this list of conditions and the following disclaimer in the
00071  *    documentation and/or other materials provided with the distribution.
00072  *
00073  * 3. Neither the name of the University nor the names of its contributors may
00074  *    be used to endorse or promote products derived from this software
00075  *    without specific prior written permission.
00076  *
00077  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00078  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00079  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00080  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00081  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00082  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00083  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00084  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00085  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00086  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00087  * POSSIBILITY OF SUCH DAMAGE.
00088  *
00089  * ----------------------------------------------------------------
00090  *
00091  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
00092  * (Royal Institute of Technology, Stockholm, Sweden).
00093  * All rights reserved.
00094  *
00095  * Redistribution and use in source and binary forms, with or without
00096  * modification, are permitted provided that the following conditions
00097  * are met:
00098  *
00099  * 1. Redistributions of source code must retain the above copyright
00100  *    notice, this list of conditions and the following disclaimer.
00101  *
00102  * 2. Redistributions in binary form must reproduce the above copyright
00103  *    notice, this list of conditions and the following disclaimer in the
00104  *    documentation and/or other materials provided with the distribution.
00105  *
00106  * 3. Neither the name of the Institute nor the names of its contributors
00107  *    may be used to endorse or promote products derived from this software
00108  *    without specific prior written permission.
00109  *
00110  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00111  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00112  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00113  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00114  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00115  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00116  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00117  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00118  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00119  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00120  * SUCH DAMAGE.
00121  */
00122 
00123 /*
00124  * XXXSRA We should omit this file entirely in Makefile.in via autoconf,
00125  * but this will keep it from generating errors until that's written.
00126  */
00127 
00128 #ifdef GSSAPI
00129 
00130 /*
00131  * XXXSRA Some of the following files are almost certainly unnecessary,
00132  * but using this list (borrowed from gssapictx.c) gets rid of some
00133  * whacky compilation errors when building with MSVC and should be
00134  * harmless in any case.
00135  */
00136 
00137 #include <config.h>
00138 
00139 #include <stdlib.h>
00140 #include <errno.h>
00141 
00142 #include <isc/buffer.h>
00143 #include <isc/dir.h>
00144 #include <isc/entropy.h>
00145 #include <isc/lex.h>
00146 #include <isc/mem.h>
00147 #include <isc/once.h>
00148 #include <isc/random.h>
00149 #include <isc/string.h>
00150 #include <isc/time.h>
00151 #include <isc/util.h>
00152 
00153 #include <dns/fixedname.h>
00154 #include <dns/name.h>
00155 #include <dns/rdata.h>
00156 #include <dns/rdataclass.h>
00157 #include <dns/result.h>
00158 #include <dns/types.h>
00159 #include <dns/keyvalues.h>
00160 #include <dns/log.h>
00161 
00162 #include <dst/gssapi.h>
00163 #include <dst/result.h>
00164 
00165 #include "dst_internal.h"
00166 
00167 /*
00168  * The API we export
00169  */
00170 #include "spnego.h"
00171 
00172 /* asn1_err.h */
00173 /* Generated from ../../../lib/asn1/asn1_err.et */
00174 
00175 #ifndef ERROR_TABLE_BASE_asn1
00176 /* these may be brought in already via gssapi_krb5.h */
00177 typedef enum asn1_error_number {
00178         ASN1_BAD_TIMEFORMAT = 1859794432,
00179         ASN1_MISSING_FIELD = 1859794433,
00180         ASN1_MISPLACED_FIELD = 1859794434,
00181         ASN1_TYPE_MISMATCH = 1859794435,
00182         ASN1_OVERFLOW = 1859794436,
00183         ASN1_OVERRUN = 1859794437,
00184         ASN1_BAD_ID = 1859794438,
00185         ASN1_BAD_LENGTH = 1859794439,
00186         ASN1_BAD_FORMAT = 1859794440,
00187         ASN1_PARSE_ERROR = 1859794441
00188 } asn1_error_number;
00189 
00190 #define ERROR_TABLE_BASE_asn1 1859794432
00191 #endif
00192 
00193 #define __asn1_common_definitions__
00194 
00195 typedef struct octet_string {
00196         size_t length;
00197         void *data;
00198 } octet_string;
00199 
00200 typedef char *general_string;
00201 
00202 typedef char *utf8_string;
00203 
00204 typedef struct oid {
00205         size_t length;
00206         unsigned *components;
00207 } oid;
00208 
00209 /* der.h */
00210 
00211 typedef enum {
00212         ASN1_C_UNIV = 0, ASN1_C_APPL = 1,
00213         ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3
00214 } Der_class;
00215 
00216 typedef enum {
00217         PRIM = 0, CONS = 1
00218 } Der_type;
00219 
00220 /* Universal tags */
00221 
00222 enum {
00223         UT_Boolean = 1,
00224         UT_Integer = 2,
00225         UT_BitString = 3,
00226         UT_OctetString = 4,
00227         UT_Null = 5,
00228         UT_OID = 6,
00229         UT_Enumerated = 10,
00230         UT_Sequence = 16,
00231         UT_Set = 17,
00232         UT_PrintableString = 19,
00233         UT_IA5String = 22,
00234         UT_UTCTime = 23,
00235         UT_GeneralizedTime = 24,
00236         UT_VisibleString = 26,
00237         UT_GeneralString = 27
00238 };
00239 
00240 #define ASN1_INDEFINITE 0xdce0deed
00241 
00242 static int
00243 der_get_length(const unsigned char *p, size_t len,
00244                size_t * val, size_t * size);
00245 
00246 static int
00247 der_get_octet_string(const unsigned char *p, size_t len,
00248                      octet_string * data, size_t * size);
00249 static int
00250 der_get_oid(const unsigned char *p, size_t len,
00251             oid * data, size_t * size);
00252 static int
00253 der_get_tag(const unsigned char *p, size_t len,
00254             Der_class * class, Der_type * type,
00255             int *tag, size_t * size);
00256 
00257 static int
00258 der_match_tag(const unsigned char *p, size_t len,
00259               Der_class class, Der_type type,
00260               int tag, size_t * size);
00261 static int
00262 der_match_tag_and_length(const unsigned char *p, size_t len,
00263                          Der_class class, Der_type type, int tag,
00264                          size_t * length_ret, size_t * size);
00265 
00266 static int
00267 decode_oid(const unsigned char *p, size_t len,
00268            oid * k, size_t * size);
00269 
00270 static int
00271 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size);
00272 
00273 static int
00274 decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *);
00275 
00276 static int
00277 der_put_int(unsigned char *p, size_t len, int val, size_t *);
00278 
00279 static int
00280 der_put_length(unsigned char *p, size_t len, size_t val, size_t *);
00281 
00282 static int
00283 der_put_octet_string(unsigned char *p, size_t len,
00284                      const octet_string * data, size_t *);
00285 static int
00286 der_put_oid(unsigned char *p, size_t len,
00287             const oid * data, size_t * size);
00288 static int
00289 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
00290             int tag, size_t *);
00291 static int
00292 der_put_length_and_tag(unsigned char *, size_t, size_t,
00293                        Der_class, Der_type, int, size_t *);
00294 
00295 static int
00296 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *);
00297 
00298 static int
00299 encode_octet_string(unsigned char *p, size_t len,
00300                     const octet_string * k, size_t *);
00301 static int
00302 encode_oid(unsigned char *p, size_t len,
00303            const oid * k, size_t *);
00304 
00305 static void
00306 free_octet_string(octet_string * k);
00307 
00308 static void
00309 free_oid  (oid * k);
00310 
00311 static size_t
00312 length_len(size_t len);
00313 
00314 static int
00315 fix_dce(size_t reallen, size_t * len);
00316 
00317 /*
00318  * Include stuff generated by the ASN.1 compiler.
00319  */
00320 
00321 #include "spnego_asn1.c"
00322 
00323 static unsigned char gss_krb5_mech_oid_bytes[] = {
00324         0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
00325 };
00326 
00327 static gss_OID_desc gss_krb5_mech_oid_desc = {
00328         sizeof(gss_krb5_mech_oid_bytes),
00329         gss_krb5_mech_oid_bytes
00330 };
00331 
00332 static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc;
00333 
00334 static unsigned char gss_mskrb5_mech_oid_bytes[] = {
00335         0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
00336 };
00337 
00338 static gss_OID_desc gss_mskrb5_mech_oid_desc = {
00339         sizeof(gss_mskrb5_mech_oid_bytes),
00340         gss_mskrb5_mech_oid_bytes
00341 };
00342 
00343 static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc;
00344 
00345 static unsigned char gss_spnego_mech_oid_bytes[] = {
00346         0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
00347 };
00348 
00349 static gss_OID_desc gss_spnego_mech_oid_desc = {
00350         sizeof(gss_spnego_mech_oid_bytes),
00351         gss_spnego_mech_oid_bytes
00352 };
00353 
00354 static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc;
00355 
00356 /* spnegokrb5_locl.h */
00357 
00358 static OM_uint32
00359 gssapi_spnego_encapsulate(OM_uint32 *,
00360                           unsigned char *,
00361                           size_t,
00362                           gss_buffer_t,
00363                           const gss_OID);
00364 
00365 static OM_uint32
00366 gssapi_spnego_decapsulate(OM_uint32 *,
00367                           gss_buffer_t,
00368                           unsigned char **,
00369                           size_t *,
00370                           const gss_OID);
00371 
00372 /* mod_auth_kerb.c */
00373 
00374 static int
00375 cmp_gss_type(gss_buffer_t token, gss_OID gssoid)
00376 {
00377         unsigned char *p;
00378         size_t len;
00379 
00380         if (token->length == 0U)
00381                 return (GSS_S_DEFECTIVE_TOKEN);
00382 
00383         p = token->value;
00384         if (*p++ != 0x60)
00385                 return (GSS_S_DEFECTIVE_TOKEN);
00386         len = *p++;
00387         if (len & 0x80) {
00388                 if ((len & 0x7f) > 4U)
00389                         return (GSS_S_DEFECTIVE_TOKEN);
00390                 p += len & 0x7f;
00391         }
00392         if (*p++ != 0x06)
00393                 return (GSS_S_DEFECTIVE_TOKEN);
00394 
00395         if (((OM_uint32) *p++) != gssoid->length)
00396                 return (GSS_S_DEFECTIVE_TOKEN);
00397 
00398         return (memcmp(p, gssoid->elements, gssoid->length));
00399 }
00400 
00401 /* accept_sec_context.c */
00402 /*
00403  * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
00404  * based on Heimdal code)
00405  */
00406 
00407 static OM_uint32
00408 code_NegTokenArg(OM_uint32 * minor_status,
00409                  const NegTokenResp * resp,
00410                  unsigned char **outbuf,
00411                  size_t * outbuf_size)
00412 {
00413         OM_uint32 ret;
00414         u_char *buf;
00415         size_t buf_size, buf_len = 0;
00416 
00417         buf_size = 1024;
00418         buf = malloc(buf_size);
00419         if (buf == NULL) {
00420                 *minor_status = ENOMEM;
00421                 return (GSS_S_FAILURE);
00422         }
00423         do {
00424                 ret = encode_NegTokenResp(buf + buf_size - 1,
00425                                           buf_size,
00426                                           resp, &buf_len);
00427                 if (ret == 0) {
00428                         size_t tmp;
00429 
00430                         ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
00431                                                      buf_size - buf_len,
00432                                                      buf_len,
00433                                                      ASN1_C_CONTEXT,
00434                                                      CONS,
00435                                                      1,
00436                                                      &tmp);
00437                         if (ret == 0)
00438                                 buf_len += tmp;
00439                 }
00440                 if (ret) {
00441                         if (ret == ASN1_OVERFLOW) {
00442                                 u_char *tmp;
00443 
00444                                 buf_size *= 2;
00445                                 tmp = realloc(buf, buf_size);
00446                                 if (tmp == NULL) {
00447                                         *minor_status = ENOMEM;
00448                                         free(buf);
00449                                         return (GSS_S_FAILURE);
00450                                 }
00451                                 buf = tmp;
00452                         } else {
00453                                 *minor_status = ret;
00454                                 free(buf);
00455                                 return (GSS_S_FAILURE);
00456                         }
00457                 }
00458         } while (ret == ASN1_OVERFLOW);
00459 
00460         *outbuf = malloc(buf_len);
00461         if (*outbuf == NULL) {
00462                 *minor_status = ENOMEM;
00463                 free(buf);
00464                 return (GSS_S_FAILURE);
00465         }
00466         memmove(*outbuf, buf + buf_size - buf_len, buf_len);
00467         *outbuf_size = buf_len;
00468 
00469         free(buf);
00470 
00471         return (GSS_S_COMPLETE);
00472 }
00473 
00474 static OM_uint32
00475 send_reject(OM_uint32 * minor_status,
00476             gss_buffer_t output_token)
00477 {
00478         NegTokenResp resp;
00479         OM_uint32 ret;
00480 
00481         resp.negState = malloc(sizeof(*resp.negState));
00482         if (resp.negState == NULL) {
00483                 *minor_status = ENOMEM;
00484                 return (GSS_S_FAILURE);
00485         }
00486         *(resp.negState) = reject;
00487 
00488         resp.supportedMech = NULL;
00489         resp.responseToken = NULL;
00490         resp.mechListMIC = NULL;
00491 
00492         ret = code_NegTokenArg(minor_status, &resp,
00493                                (unsigned char **)&output_token->value,
00494                                &output_token->length);
00495         free_NegTokenResp(&resp);
00496         if (ret)
00497                 return (ret);
00498 
00499         return (GSS_S_BAD_MECH);
00500 }
00501 
00502 static OM_uint32
00503 send_accept(OM_uint32 * minor_status,
00504             gss_buffer_t output_token,
00505             gss_buffer_t mech_token,
00506             const gss_OID pref)
00507 {
00508         NegTokenResp resp;
00509         OM_uint32 ret;
00510 
00511         memset(&resp, 0, sizeof(resp));
00512         resp.negState = malloc(sizeof(*resp.negState));
00513         if (resp.negState == NULL) {
00514                 *minor_status = ENOMEM;
00515                 return (GSS_S_FAILURE);
00516         }
00517         *(resp.negState) = accept_completed;
00518 
00519         resp.supportedMech = malloc(sizeof(*resp.supportedMech));
00520         if (resp.supportedMech == NULL) {
00521                 free_NegTokenResp(&resp);
00522                 *minor_status = ENOMEM;
00523                 return (GSS_S_FAILURE);
00524         }
00525         ret = der_get_oid(pref->elements,
00526                           pref->length,
00527                           resp.supportedMech,
00528                           NULL);
00529         if (ret) {
00530                 free_NegTokenResp(&resp);
00531                 *minor_status = ENOMEM;
00532                 return (GSS_S_FAILURE);
00533         }
00534         if (mech_token != NULL && mech_token->length != 0U) {
00535                 resp.responseToken = malloc(sizeof(*resp.responseToken));
00536                 if (resp.responseToken == NULL) {
00537                         free_NegTokenResp(&resp);
00538                         *minor_status = ENOMEM;
00539                         return (GSS_S_FAILURE);
00540                 }
00541                 resp.responseToken->length = mech_token->length;
00542                 resp.responseToken->data = mech_token->value;
00543         }
00544 
00545         ret = code_NegTokenArg(minor_status, &resp,
00546                                (unsigned char **)&output_token->value,
00547                                &output_token->length);
00548         if (resp.responseToken != NULL) {
00549                 free(resp.responseToken);
00550                 resp.responseToken = NULL;
00551         }
00552         free_NegTokenResp(&resp);
00553         if (ret)
00554                 return (ret);
00555 
00556         return (GSS_S_COMPLETE);
00557 }
00558 
00559 OM_uint32
00560 gss_accept_sec_context_spnego(OM_uint32 *minor_status,
00561                               gss_ctx_id_t *context_handle,
00562                               const gss_cred_id_t acceptor_cred_handle,
00563                               const gss_buffer_t input_token_buffer,
00564                               const gss_channel_bindings_t input_chan_bindings,
00565                               gss_name_t *src_name,
00566                               gss_OID *mech_type,
00567                               gss_buffer_t output_token,
00568                               OM_uint32 *ret_flags,
00569                               OM_uint32 *time_rec,
00570                               gss_cred_id_t *delegated_cred_handle)
00571 {
00572         NegTokenInit init_token;
00573         OM_uint32 major_status;
00574         OM_uint32 minor_status2;
00575         gss_buffer_desc ibuf, obuf;
00576         gss_buffer_t ot = NULL;
00577         gss_OID pref = GSS_KRB5_MECH;
00578         unsigned char *buf;
00579         size_t buf_size;
00580         size_t len, taglen, ni_len;
00581         int found = 0;
00582         int ret;
00583         unsigned i;
00584 
00585         /*
00586          * Before doing anything else, see whether this is a SPNEGO
00587          * PDU.  If not, dispatch to the GSSAPI library and get out.
00588          */
00589 
00590         if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH))
00591                 return (gss_accept_sec_context(minor_status,
00592                                                context_handle,
00593                                                acceptor_cred_handle,
00594                                                input_token_buffer,
00595                                                input_chan_bindings,
00596                                                src_name,
00597                                                mech_type,
00598                                                output_token,
00599                                                ret_flags,
00600                                                time_rec,
00601                                                delegated_cred_handle));
00602 
00603         /*
00604          * If we get here, it's SPNEGO.
00605          */
00606 
00607         memset(&init_token, 0, sizeof(init_token));
00608 
00609         ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
00610                                         &buf, &buf_size, GSS_SPNEGO_MECH);
00611         if (ret)
00612                 return (ret);
00613 
00614         ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS,
00615                                        0, &len, &taglen);
00616         if (ret)
00617                 return (ret);
00618 
00619         ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
00620         if (ret) {
00621                 *minor_status = EINVAL; /* XXX */
00622                 return (GSS_S_DEFECTIVE_TOKEN);
00623         }
00624 
00625         for (i = 0; !found && i < init_token.mechTypes.len; ++i) {
00626                 unsigned char mechbuf[17];
00627                 size_t mech_len;
00628 
00629                 ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1,
00630                                   sizeof(mechbuf),
00631                                   &init_token.mechTypes.val[i],
00632                                   &mech_len);
00633                 if (ret) {
00634                         free_NegTokenInit(&init_token);
00635                         return (GSS_S_DEFECTIVE_TOKEN);
00636                 }
00637                 if (mech_len == GSS_KRB5_MECH->length &&
00638                     memcmp(GSS_KRB5_MECH->elements,
00639                            mechbuf + sizeof(mechbuf) - mech_len,
00640                            mech_len) == 0) {
00641                         found = 1;
00642                         break;
00643                 }
00644                 if (mech_len == GSS_MSKRB5_MECH->length &&
00645                     memcmp(GSS_MSKRB5_MECH->elements,
00646                            mechbuf + sizeof(mechbuf) - mech_len,
00647                            mech_len) == 0) {
00648                         found = 1;
00649                         if (i == 0)
00650                                 pref = GSS_MSKRB5_MECH;
00651                         break;
00652                 }
00653         }
00654 
00655         if (!found) {
00656                 free_NegTokenInit(&init_token);
00657                 return (send_reject(minor_status, output_token));
00658         }
00659 
00660         if (i == 0 && init_token.mechToken != NULL) {
00661                 ibuf.length = init_token.mechToken->length;
00662                 ibuf.value = init_token.mechToken->data;
00663 
00664                 major_status = gss_accept_sec_context(minor_status,
00665                                                       context_handle,
00666                                                       acceptor_cred_handle,
00667                                                       &ibuf,
00668                                                       input_chan_bindings,
00669                                                       src_name,
00670                                                       mech_type,
00671                                                       &obuf,
00672                                                       ret_flags,
00673                                                       time_rec,
00674                                                       delegated_cred_handle);
00675                 if (GSS_ERROR(major_status)) {
00676                         free_NegTokenInit(&init_token);
00677                         send_reject(&minor_status2, output_token);
00678                         return (major_status);
00679                 }
00680                 ot = &obuf;
00681         }
00682         ret = send_accept(&minor_status2, output_token, ot, pref);
00683         free_NegTokenInit(&init_token);
00684         if (ot != NULL && ot->length != 0U)
00685                 gss_release_buffer(&minor_status2, ot);
00686 
00687         return (ret);
00688 }
00689 
00690 /* decapsulate.c */
00691 
00692 static OM_uint32
00693 gssapi_verify_mech_header(u_char ** str,
00694                           size_t total_len,
00695                           const gss_OID mech)
00696 {
00697         size_t len, len_len, mech_len, foo;
00698         int e;
00699         u_char *p = *str;
00700 
00701         if (total_len < 1U)
00702                 return (GSS_S_DEFECTIVE_TOKEN);
00703         if (*p++ != 0x60)
00704                 return (GSS_S_DEFECTIVE_TOKEN);
00705         e = der_get_length(p, total_len - 1, &len, &len_len);
00706         if (e || 1 + len_len + len != total_len)
00707                 return (GSS_S_DEFECTIVE_TOKEN);
00708         p += len_len;
00709         if (*p++ != 0x06)
00710                 return (GSS_S_DEFECTIVE_TOKEN);
00711         e = der_get_length(p, total_len - 1 - len_len - 1,
00712                            &mech_len, &foo);
00713         if (e)
00714                 return (GSS_S_DEFECTIVE_TOKEN);
00715         p += foo;
00716         if (mech_len != mech->length)
00717                 return (GSS_S_BAD_MECH);
00718         if (memcmp(p, mech->elements, mech->length) != 0)
00719                 return (GSS_S_BAD_MECH);
00720         p += mech_len;
00721         *str = p;
00722         return (GSS_S_COMPLETE);
00723 }
00724 
00725 /*
00726  * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
00727  * not copy data, so just free `in_token'.
00728  */
00729 
00730 static OM_uint32
00731 gssapi_spnego_decapsulate(OM_uint32 *minor_status,
00732                           gss_buffer_t input_token_buffer,
00733                           unsigned char **buf,
00734                           size_t *buf_len,
00735                           const gss_OID mech)
00736 {
00737         u_char *p;
00738         OM_uint32 ret;
00739 
00740         p = input_token_buffer->value;
00741         ret = gssapi_verify_mech_header(&p,
00742                                         input_token_buffer->length,
00743                                         mech);
00744         if (ret) {
00745                 *minor_status = ret;
00746                 return (GSS_S_FAILURE);
00747         }
00748         *buf_len = input_token_buffer->length -
00749                 (p - (u_char *) input_token_buffer->value);
00750         *buf = p;
00751         return (GSS_S_COMPLETE);
00752 }
00753 
00754 /* der_free.c */
00755 
00756 static void
00757 free_octet_string(octet_string *k)
00758 {
00759         free(k->data);
00760         k->data = NULL;
00761 }
00762 
00763 static void
00764 free_oid(oid *k)
00765 {
00766         free(k->components);
00767         k->components = NULL;
00768 }
00769 
00770 /* der_get.c */
00771 
00772 /*
00773  * All decoding functions take a pointer `p' to first position in which to
00774  * read, from the left, `len' which means the maximum number of characters we
00775  * are able to read, `ret' were the value will be returned and `size' where
00776  * the number of used bytes is stored. Either 0 or an error code is returned.
00777  */
00778 
00779 static int
00780 der_get_unsigned(const unsigned char *p, size_t len,
00781                  unsigned *ret, size_t *size)
00782 {
00783         unsigned val = 0;
00784         size_t oldlen = len;
00785 
00786         while (len--)
00787                 val = val * 256 + *p++;
00788         *ret = val;
00789         if (size)
00790                 *size = oldlen;
00791         return (0);
00792 }
00793 
00794 static int
00795 der_get_int(const unsigned char *p, size_t len,
00796             int *ret, size_t *size)
00797 {
00798         int val = 0;
00799         size_t oldlen = len;
00800 
00801         if (len > 0U) {
00802                 val = (signed char)*p++;
00803                 while (--len)
00804                         val = val * 256 + *p++;
00805         }
00806         *ret = val;
00807         if (size)
00808                 *size = oldlen;
00809         return (0);
00810 }
00811 
00812 static int
00813 der_get_length(const unsigned char *p, size_t len,
00814                size_t *val, size_t *size)
00815 {
00816         size_t v;
00817 
00818         if (len <= 0U)
00819                 return (ASN1_OVERRUN);
00820         --len;
00821         v = *p++;
00822         if (v < 128U) {
00823                 *val = v;
00824                 if (size)
00825                         *size = 1;
00826         } else {
00827                 int e;
00828                 size_t l;
00829                 unsigned tmp;
00830 
00831                 if (v == 0x80U) {
00832                         *val = ASN1_INDEFINITE;
00833                         if (size)
00834                                 *size = 1;
00835                         return (0);
00836                 }
00837                 v &= 0x7F;
00838                 if (len < v)
00839                         return (ASN1_OVERRUN);
00840                 e = der_get_unsigned(p, v, &tmp, &l);
00841                 if (e)
00842                         return (e);
00843                 *val = tmp;
00844                 if (size)
00845                         *size = l + 1;
00846         }
00847         return (0);
00848 }
00849 
00850 static int
00851 der_get_octet_string(const unsigned char *p, size_t len,
00852                      octet_string *data, size_t *size)
00853 {
00854         data->length = len;
00855         if (len != 0U) {
00856                 data->data = malloc(len);
00857                 if (data->data == NULL)
00858                         return (ENOMEM);
00859                 memmove(data->data, p, len);
00860         } else
00861                 data->data = NULL;
00862         if (size)
00863                 *size = len;
00864         return (0);
00865 }
00866 
00867 static int
00868 der_get_oid(const unsigned char *p, size_t len,
00869             oid *data, size_t *size)
00870 {
00871         int n;
00872         size_t oldlen = len;
00873 
00874         data->components = NULL;
00875         data->length = 0;
00876         if (len < 1U)
00877                 return (ASN1_OVERRUN);
00878 
00879         data->components = malloc(len * sizeof(*data->components));
00880         if (data->components == NULL && len != 0U)
00881                 return (ENOMEM);
00882         data->components[0] = (*p) / 40;
00883         data->components[1] = (*p) % 40;
00884         --len;
00885         ++p;
00886         for (n = 2; len > 0U; ++n) {
00887                 unsigned u = 0;
00888 
00889                 do {
00890                         --len;
00891                         u = u * 128 + (*p++ % 128);
00892                 } while (len > 0U && p[-1] & 0x80);
00893                 data->components[n] = u;
00894         }
00895         if (p[-1] & 0x80) {
00896                 free_oid(data);
00897                 return (ASN1_OVERRUN);
00898         }
00899         data->length = n;
00900         if (size)
00901                 *size = oldlen;
00902         return (0);
00903 }
00904 
00905 static int
00906 der_get_tag(const unsigned char *p, size_t len,
00907             Der_class *class, Der_type *type,
00908             int *tag, size_t *size)
00909 {
00910         if (len < 1U)
00911                 return (ASN1_OVERRUN);
00912         *class = (Der_class) (((*p) >> 6) & 0x03);
00913         *type = (Der_type) (((*p) >> 5) & 0x01);
00914         *tag = (*p) & 0x1F;
00915         if (size)
00916                 *size = 1;
00917         return (0);
00918 }
00919 
00920 static int
00921 der_match_tag(const unsigned char *p, size_t len,
00922               Der_class class, Der_type type,
00923               int tag, size_t *size)
00924 {
00925         size_t l;
00926         Der_class thisclass;
00927         Der_type thistype;
00928         int thistag;
00929         int e;
00930 
00931         e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l);
00932         if (e)
00933                 return (e);
00934         if (class != thisclass || type != thistype)
00935                 return (ASN1_BAD_ID);
00936         if (tag > thistag)
00937                 return (ASN1_MISPLACED_FIELD);
00938         if (tag < thistag)
00939                 return (ASN1_MISSING_FIELD);
00940         if (size)
00941                 *size = l;
00942         return (0);
00943 }
00944 
00945 static int
00946 der_match_tag_and_length(const unsigned char *p, size_t len,
00947                          Der_class class, Der_type type, int tag,
00948                          size_t *length_ret, size_t *size)
00949 {
00950         size_t l, ret = 0;
00951         int e;
00952 
00953         e = der_match_tag(p, len, class, type, tag, &l);
00954         if (e)
00955                 return (e);
00956         p += l;
00957         len -= l;
00958         ret += l;
00959         e = der_get_length(p, len, length_ret, &l);
00960         if (e)
00961                 return (e);
00962         /* p += l; */
00963         len -= l;
00964         POST(len);
00965         ret += l;
00966         if (size)
00967                 *size = ret;
00968         return (0);
00969 }
00970 
00971 static int
00972 decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size)
00973 {
00974         size_t ret = 0;
00975         size_t l, reallen;
00976         int e;
00977 
00978         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
00979         if (e)
00980                 return (e);
00981         p += l;
00982         len -= l;
00983         ret += l;
00984         e = der_get_length(p, len, &reallen, &l);
00985         if (e)
00986                 return (e);
00987         p += l;
00988         len -= l;
00989         ret += l;
00990         e = der_get_int(p, reallen, num, &l);
00991         if (e)
00992                 return (e);
00993         p += l;
00994         len -= l;
00995         POST(p); POST(len);
00996         ret += l;
00997         if (size)
00998                 *size = ret;
00999         return (0);
01000 }
01001 
01002 static int
01003 decode_octet_string(const unsigned char *p, size_t len,
01004                     octet_string *k, size_t *size)
01005 {
01006         size_t ret = 0;
01007         size_t l;
01008         int e;
01009         size_t slen;
01010 
01011         k->data = NULL;
01012         k->length = 0;
01013 
01014         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
01015         if (e)
01016                 return (e);
01017         p += l;
01018         len -= l;
01019         ret += l;
01020 
01021         e = der_get_length(p, len, &slen, &l);
01022         if (e)
01023                 return (e);
01024         p += l;
01025         len -= l;
01026         ret += l;
01027         if (len < slen)
01028                 return (ASN1_OVERRUN);
01029 
01030         e = der_get_octet_string(p, slen, k, &l);
01031         if (e)
01032                 return (e);
01033         p += l;
01034         len -= l;
01035         POST(p); POST(len);
01036         ret += l;
01037         if (size)
01038                 *size = ret;
01039         return (0);
01040 }
01041 
01042 static int
01043 decode_oid(const unsigned char *p, size_t len,
01044            oid *k, size_t *size)
01045 {
01046         size_t ret = 0;
01047         size_t l;
01048         int e;
01049         size_t slen;
01050 
01051         e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
01052         if (e)
01053                 return (e);
01054         p += l;
01055         len -= l;
01056         ret += l;
01057 
01058         e = der_get_length(p, len, &slen, &l);
01059         if (e)
01060                 return (e);
01061         p += l;
01062         len -= l;
01063         ret += l;
01064         if (len < slen)
01065                 return (ASN1_OVERRUN);
01066 
01067         e = der_get_oid(p, slen, k, &l);
01068         if (e)
01069                 return (e);
01070         p += l;
01071         len -= l;
01072         POST(p); POST(len);
01073         ret += l;
01074         if (size)
01075                 *size = ret;
01076         return (0);
01077 }
01078 
01079 static int
01080 fix_dce(size_t reallen, size_t *len)
01081 {
01082         if (reallen == ASN1_INDEFINITE)
01083                 return (1);
01084         if (*len < reallen)
01085                 return (-1);
01086         *len = reallen;
01087         return (0);
01088 }
01089 
01090 /* der_length.c */
01091 
01092 static size_t
01093 len_unsigned(unsigned val)
01094 {
01095         size_t ret = 0;
01096 
01097         do {
01098                 ++ret;
01099                 val /= 256;
01100         } while (val);
01101         return (ret);
01102 }
01103 
01104 static size_t
01105 length_len(size_t len)
01106 {
01107         if (len < 128U)
01108                 return (1);
01109         else
01110                 return (len_unsigned((unsigned int)len) + 1);
01111 }
01112 
01113 
01114 /* der_put.c */
01115 
01116 /*
01117  * All encoding functions take a pointer `p' to first position in which to
01118  * write, from the right, `len' which means the maximum number of characters
01119  * we are able to write.  The function returns the number of characters
01120  * written in `size' (if non-NULL). The return value is 0 or an error.
01121  */
01122 
01123 static int
01124 der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size)
01125 {
01126         unsigned char *base = p;
01127 
01128         if (val) {
01129                 while (len > 0U && val) {
01130                         *p-- = val % 256;
01131                         val /= 256;
01132                         --len;
01133                 }
01134                 if (val != 0)
01135                         return (ASN1_OVERFLOW);
01136                 else {
01137                         *size = base - p;
01138                         return (0);
01139                 }
01140         } else if (len < 1U)
01141                 return (ASN1_OVERFLOW);
01142         else {
01143                 *p = 0;
01144                 *size = 1;
01145                 return (0);
01146         }
01147 }
01148 
01149 static int
01150 der_put_int(unsigned char *p, size_t len, int val, size_t *size)
01151 {
01152         unsigned char *base = p;
01153 
01154         if (val >= 0) {
01155                 do {
01156                         if (len < 1U)
01157                                 return (ASN1_OVERFLOW);
01158                         *p-- = val % 256;
01159                         len--;
01160                         val /= 256;
01161                 } while (val);
01162                 if (p[1] >= 128) {
01163                         if (len < 1U)
01164                                 return (ASN1_OVERFLOW);
01165                         *p-- = 0;
01166                         len--;
01167                 }
01168         } else {
01169                 val = ~val;
01170                 do {
01171                         if (len < 1U)
01172                                 return (ASN1_OVERFLOW);
01173                         *p-- = ~(val % 256);
01174                         len--;
01175                         val /= 256;
01176                 } while (val);
01177                 if (p[1] < 128) {
01178                         if (len < 1U)
01179                                 return (ASN1_OVERFLOW);
01180                         *p-- = 0xff;
01181                         len--;
01182                 }
01183         }
01184         *size = base - p;
01185         return (0);
01186 }
01187 
01188 static int
01189 der_put_length(unsigned char *p, size_t len, size_t val, size_t *size)
01190 {
01191         if (len < 1U)
01192                 return (ASN1_OVERFLOW);
01193         if (val < 128U) {
01194                 *p = (unsigned char)val;
01195                 *size = 1;
01196                 return (0);
01197         } else {
01198                 size_t l;
01199                 int e;
01200 
01201                 e = der_put_unsigned(p, len - 1, (unsigned int)val, &l);
01202                 if (e)
01203                         return (e);
01204                 p -= l;
01205                 *p = 0x80 | (unsigned char)l;
01206                 *size = l + 1;
01207                 return (0);
01208         }
01209 }
01210 
01211 static int
01212 der_put_octet_string(unsigned char *p, size_t len,
01213                      const octet_string *data, size_t *size)
01214 {
01215         if (len < data->length)
01216                 return (ASN1_OVERFLOW);
01217         p -= data->length;
01218         len -= data->length;
01219         POST(len);
01220         memmove(p + 1, data->data, data->length);
01221         *size = data->length;
01222         return (0);
01223 }
01224 
01225 static int
01226 der_put_oid(unsigned char *p, size_t len,
01227             const oid *data, size_t *size)
01228 {
01229         unsigned char *base = p;
01230         size_t n;
01231 
01232         for (n = data->length; n >= 3u; --n) {
01233                 unsigned        u = data->components[n - 1];
01234 
01235                 if (len < 1U)
01236                         return (ASN1_OVERFLOW);
01237                 *p-- = u % 128;
01238                 u /= 128;
01239                 --len;
01240                 while (u > 0) {
01241                         if (len < 1U)
01242                                 return (ASN1_OVERFLOW);
01243                         *p-- = 128 + u % 128;
01244                         u /= 128;
01245                         --len;
01246                 }
01247         }
01248         if (len < 1U)
01249                 return (ASN1_OVERFLOW);
01250         *p-- = 40 * data->components[0] + data->components[1];
01251         *size = base - p;
01252         return (0);
01253 }
01254 
01255 static int
01256 der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
01257             int tag, size_t *size)
01258 {
01259         if (len < 1U)
01260                 return (ASN1_OVERFLOW);
01261         *p = (class << 6) | (type << 5) | tag;  /* XXX */
01262         *size = 1;
01263         return (0);
01264 }
01265 
01266 static int
01267 der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
01268                        Der_class class, Der_type type, int tag, size_t *size)
01269 {
01270         size_t ret = 0;
01271         size_t l;
01272         int e;
01273 
01274         e = der_put_length(p, len, len_val, &l);
01275         if (e)
01276                 return (e);
01277         p -= l;
01278         len -= l;
01279         ret += l;
01280         e = der_put_tag(p, len, class, type, tag, &l);
01281         if (e)
01282                 return (e);
01283         p -= l;
01284         len -= l;
01285         POST(p); POST(len);
01286         ret += l;
01287         *size = ret;
01288         return (0);
01289 }
01290 
01291 static int
01292 encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size)
01293 {
01294         unsigned num = *(const unsigned *)data;
01295         size_t ret = 0;
01296         size_t l;
01297         int e;
01298 
01299         e = der_put_int(p, len, num, &l);
01300         if (e)
01301                 return (e);
01302         p -= l;
01303         len -= l;
01304         ret += l;
01305         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
01306         if (e)
01307                 return (e);
01308         p -= l;
01309         len -= l;
01310         POST(p); POST(len);
01311         ret += l;
01312         *size = ret;
01313         return (0);
01314 }
01315 
01316 static int
01317 encode_octet_string(unsigned char *p, size_t len,
01318                     const octet_string *k, size_t *size)
01319 {
01320         size_t ret = 0;
01321         size_t l;
01322         int e;
01323 
01324         e = der_put_octet_string(p, len, k, &l);
01325         if (e)
01326                 return (e);
01327         p -= l;
01328         len -= l;
01329         ret += l;
01330         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
01331         if (e)
01332                 return (e);
01333         p -= l;
01334         len -= l;
01335         POST(p); POST(len);
01336         ret += l;
01337         *size = ret;
01338         return (0);
01339 }
01340 
01341 static int
01342 encode_oid(unsigned char *p, size_t len,
01343            const oid *k, size_t *size)
01344 {
01345         size_t ret = 0;
01346         size_t l;
01347         int e;
01348 
01349         e = der_put_oid(p, len, k, &l);
01350         if (e)
01351                 return (e);
01352         p -= l;
01353         len -= l;
01354         ret += l;
01355         e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
01356         if (e)
01357                 return (e);
01358         p -= l;
01359         len -= l;
01360         POST(p); POST(len);
01361         ret += l;
01362         *size = ret;
01363         return (0);
01364 }
01365 
01366 
01367 /* encapsulate.c */
01368 
01369 static void
01370 gssapi_encap_length(size_t data_len,
01371                     size_t *len,
01372                     size_t *total_len,
01373                     const gss_OID mech)
01374 {
01375         size_t len_len;
01376 
01377         *len = 1 + 1 + mech->length + data_len;
01378 
01379         len_len = length_len(*len);
01380 
01381         *total_len = 1 + len_len + *len;
01382 }
01383 
01384 static u_char *
01385 gssapi_mech_make_header(u_char *p,
01386                         size_t len,
01387                         const gss_OID mech)
01388 {
01389         int e;
01390         size_t len_len, foo;
01391 
01392         *p++ = 0x60;
01393         len_len = length_len(len);
01394         e = der_put_length(p + len_len - 1, len_len, len, &foo);
01395         if (e || foo != len_len)
01396                 return (NULL);
01397         p += len_len;
01398         *p++ = 0x06;
01399         *p++ = mech->length;
01400         memmove(p, mech->elements, mech->length);
01401         p += mech->length;
01402         return (p);
01403 }
01404 
01405 /*
01406  * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
01407  */
01408 
01409 static OM_uint32
01410 gssapi_spnego_encapsulate(OM_uint32 * minor_status,
01411                           unsigned char *buf,
01412                           size_t buf_size,
01413                           gss_buffer_t output_token,
01414                           const gss_OID mech)
01415 {
01416         size_t len, outer_len;
01417         u_char *p;
01418 
01419         gssapi_encap_length(buf_size, &len, &outer_len, mech);
01420 
01421         output_token->length = outer_len;
01422         output_token->value = malloc(outer_len);
01423         if (output_token->value == NULL) {
01424                 *minor_status = ENOMEM;
01425                 return (GSS_S_FAILURE);
01426         }
01427         p = gssapi_mech_make_header(output_token->value, len, mech);
01428         if (p == NULL) {
01429                 if (output_token->length != 0U)
01430                         gss_release_buffer(minor_status, output_token);
01431                 return (GSS_S_FAILURE);
01432         }
01433         memmove(p, buf, buf_size);
01434         return (GSS_S_COMPLETE);
01435 }
01436 
01437 /* init_sec_context.c */
01438 /*
01439  * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
01440  * based on Heimdal code)
01441  */
01442 
01443 static int
01444 add_mech(MechTypeList * mech_list, gss_OID mech)
01445 {
01446         MechType *tmp;
01447         int ret;
01448 
01449         tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
01450         if (tmp == NULL)
01451                 return (ENOMEM);
01452         mech_list->val = tmp;
01453 
01454         ret = der_get_oid(mech->elements, mech->length,
01455                           &mech_list->val[mech_list->len], NULL);
01456         if (ret)
01457                 return (ret);
01458 
01459         mech_list->len++;
01460         return (0);
01461 }
01462 
01463 /*
01464  * return the length of the mechanism in token or -1
01465  * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
01466  */
01467 
01468 static ssize_t
01469 gssapi_krb5_get_mech(const u_char *ptr,
01470                      size_t total_len,
01471                      const u_char **mech_ret)
01472 {
01473         size_t len, len_len, mech_len, foo;
01474         const u_char *p = ptr;
01475         int e;
01476 
01477         if (total_len < 1U)
01478                 return (-1);
01479         if (*p++ != 0x60)
01480                 return (-1);
01481         e = der_get_length (p, total_len - 1, &len, &len_len);
01482         if (e || 1 + len_len + len != total_len)
01483                 return (-1);
01484         p += len_len;
01485         if (*p++ != 0x06)
01486                 return (-1);
01487         e = der_get_length (p, total_len - 1 - len_len - 1,
01488                             &mech_len, &foo);
01489         if (e)
01490                 return (-1);
01491         p += foo;
01492         *mech_ret = p;
01493         return (mech_len);
01494 }
01495 
01496 static OM_uint32
01497 spnego_initial(OM_uint32 *minor_status,
01498                const gss_cred_id_t initiator_cred_handle,
01499                gss_ctx_id_t *context_handle,
01500                const gss_name_t target_name,
01501                const gss_OID mech_type,
01502                OM_uint32 req_flags,
01503                OM_uint32 time_req,
01504                const gss_channel_bindings_t input_chan_bindings,
01505                const gss_buffer_t input_token,
01506                gss_OID *actual_mech_type,
01507                gss_buffer_t output_token,
01508                OM_uint32 *ret_flags,
01509                OM_uint32 *time_rec)
01510 {
01511         NegTokenInit token_init;
01512         OM_uint32 major_status, minor_status2;
01513         gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
01514         unsigned char *buf = NULL;
01515         size_t buf_size;
01516         size_t len;
01517         int ret;
01518 
01519         (void)mech_type;
01520 
01521         memset(&token_init, 0, sizeof(token_init));
01522 
01523         ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH);
01524         if (ret) {
01525                 *minor_status = ret;
01526                 ret = GSS_S_FAILURE;
01527                 goto end;
01528         }
01529 
01530         major_status = gss_init_sec_context(minor_status,
01531                                             initiator_cred_handle,
01532                                             context_handle,
01533                                             target_name,
01534                                             GSS_KRB5_MECH,
01535                                             req_flags,
01536                                             time_req,
01537                                             input_chan_bindings,
01538                                             input_token,
01539                                             actual_mech_type,
01540                                             &krb5_output_token,
01541                                             ret_flags,
01542                                             time_rec);
01543         if (GSS_ERROR(major_status)) {
01544                 ret = major_status;
01545                 goto end;
01546         }
01547         if (krb5_output_token.length > 0U) {
01548                 token_init.mechToken = malloc(sizeof(*token_init.mechToken));
01549                 if (token_init.mechToken == NULL) {
01550                         *minor_status = ENOMEM;
01551                         ret = GSS_S_FAILURE;
01552                         goto end;
01553                 }
01554                 token_init.mechToken->data = krb5_output_token.value;
01555                 token_init.mechToken->length = krb5_output_token.length;
01556         }
01557         /*
01558          * The MS implementation of SPNEGO seems to not like the mechListMIC
01559          * field, so we omit it (it's optional anyway)
01560          */
01561 
01562         buf_size = 1024;
01563         buf = malloc(buf_size);
01564         if (buf == NULL) {
01565                 *minor_status = ENOMEM;
01566                 ret = GSS_S_FAILURE;
01567                 goto end;
01568         }
01569 
01570         do {
01571                 ret = encode_NegTokenInit(buf + buf_size - 1,
01572                                           buf_size,
01573                                           &token_init, &len);
01574                 if (ret == 0) {
01575                         size_t tmp;
01576 
01577                         ret = der_put_length_and_tag(buf + buf_size - len - 1,
01578                                                      buf_size - len,
01579                                                      len,
01580                                                      ASN1_C_CONTEXT,
01581                                                      CONS,
01582                                                      0,
01583                                                      &tmp);
01584                         if (ret == 0)
01585                                 len += tmp;
01586                 }
01587                 if (ret) {
01588                         if (ret == ASN1_OVERFLOW) {
01589                                 u_char *tmp;
01590 
01591                                 buf_size *= 2;
01592                                 tmp = realloc(buf, buf_size);
01593                                 if (tmp == NULL) {
01594                                         *minor_status = ENOMEM;
01595                                         ret = GSS_S_FAILURE;
01596                                         goto end;
01597                                 }
01598                                 buf = tmp;
01599                         } else {
01600                                 *minor_status = ret;
01601                                 ret = GSS_S_FAILURE;
01602                                 goto end;
01603                         }
01604                 }
01605         } while (ret == ASN1_OVERFLOW);
01606 
01607         ret = gssapi_spnego_encapsulate(minor_status,
01608                                         buf + buf_size - len, len,
01609                                         output_token, GSS_SPNEGO_MECH);
01610         if (ret == GSS_S_COMPLETE)
01611                 ret = major_status;
01612 
01613 end:
01614         if (token_init.mechToken != NULL) {
01615                 free(token_init.mechToken);
01616                 token_init.mechToken = NULL;
01617         }
01618         free_NegTokenInit(&token_init);
01619         if (krb5_output_token.length != 0U)
01620                 gss_release_buffer(&minor_status2, &krb5_output_token);
01621         if (buf)
01622                 free(buf);
01623 
01624         return (ret);
01625 }
01626 
01627 static OM_uint32
01628 spnego_reply(OM_uint32 *minor_status,
01629              const gss_cred_id_t initiator_cred_handle,
01630              gss_ctx_id_t *context_handle,
01631              const gss_name_t target_name,
01632              const gss_OID mech_type,
01633              OM_uint32 req_flags,
01634              OM_uint32 time_req,
01635              const gss_channel_bindings_t input_chan_bindings,
01636              const gss_buffer_t input_token,
01637              gss_OID *actual_mech_type,
01638              gss_buffer_t output_token,
01639              OM_uint32 *ret_flags,
01640              OM_uint32 *time_rec)
01641 {
01642         OM_uint32 ret;
01643         NegTokenResp resp;
01644         unsigned char *buf;
01645         size_t buf_size;
01646         u_char oidbuf[17];
01647         size_t oidlen;
01648         gss_buffer_desc sub_token;
01649         ssize_t mech_len;
01650         const u_char *p;
01651         size_t len, taglen;
01652 
01653         (void)mech_type;
01654 
01655         output_token->length = 0;
01656         output_token->value  = NULL;
01657 
01658         /*
01659          * SPNEGO doesn't include gss wrapping on SubsequentContextToken
01660          * like the Kerberos 5 mech does. But lets check for it anyway.
01661          */
01662 
01663         mech_len = gssapi_krb5_get_mech(input_token->value,
01664                                         input_token->length,
01665                                         &p);
01666 
01667         if (mech_len < 0) {
01668                 buf = input_token->value;
01669                 buf_size = input_token->length;
01670         } else if ((size_t)mech_len == GSS_KRB5_MECH->length &&
01671                    memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0)
01672                 return (gss_init_sec_context(minor_status,
01673                                              initiator_cred_handle,
01674                                              context_handle,
01675                                              target_name,
01676                                              GSS_KRB5_MECH,
01677                                              req_flags,
01678                                              time_req,
01679                                              input_chan_bindings,
01680                                              input_token,
01681                                              actual_mech_type,
01682                                              output_token,
01683                                              ret_flags,
01684                                              time_rec));
01685         else if ((size_t)mech_len == GSS_SPNEGO_MECH->length &&
01686                  memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) {
01687                 ret = gssapi_spnego_decapsulate(minor_status,
01688                                                 input_token,
01689                                                 &buf,
01690                                                 &buf_size,
01691                                                 GSS_SPNEGO_MECH);
01692                 if (ret)
01693                         return (ret);
01694         } else
01695                 return (GSS_S_BAD_MECH);
01696 
01697         ret = der_match_tag_and_length(buf, buf_size,
01698                                        ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
01699         if (ret)
01700                 return (ret);
01701 
01702         if(len > buf_size - taglen)
01703                 return (ASN1_OVERRUN);
01704 
01705         ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL);
01706         if (ret) {
01707                 free_NegTokenResp(&resp);
01708                 *minor_status = ENOMEM;
01709                 return (GSS_S_FAILURE);
01710         }
01711 
01712         if (resp.negState == NULL ||
01713             *(resp.negState) == reject ||
01714             resp.supportedMech == NULL) {
01715                 free_NegTokenResp(&resp);
01716                 return (GSS_S_BAD_MECH);
01717         }
01718 
01719         ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
01720                           sizeof(oidbuf),
01721                           resp.supportedMech,
01722                           &oidlen);
01723         if (ret || oidlen != GSS_KRB5_MECH->length ||
01724             memcmp(oidbuf + sizeof(oidbuf) - oidlen,
01725                    GSS_KRB5_MECH->elements,
01726                    oidlen) != 0) {
01727                 free_NegTokenResp(&resp);
01728                 return GSS_S_BAD_MECH;
01729         }
01730 
01731         if (resp.responseToken != NULL) {
01732                 sub_token.length = resp.responseToken->length;
01733                 sub_token.value  = resp.responseToken->data;
01734         } else {
01735                 sub_token.length = 0;
01736                 sub_token.value  = NULL;
01737         }
01738 
01739         ret = gss_init_sec_context(minor_status,
01740                                    initiator_cred_handle,
01741                                    context_handle,
01742                                    target_name,
01743                                    GSS_KRB5_MECH,
01744                                    req_flags,
01745                                    time_req,
01746                                    input_chan_bindings,
01747                                    &sub_token,
01748                                    actual_mech_type,
01749                                    output_token,
01750                                    ret_flags,
01751                                    time_rec);
01752         if (ret) {
01753                 free_NegTokenResp(&resp);
01754                 return (ret);
01755         }
01756 
01757         /*
01758          * XXXSRA I don't think this limited implementation ever needs
01759          * to check the MIC -- our preferred mechanism (Kerberos)
01760          * authenticates its own messages and is the only mechanism
01761          * we'll accept, so if the mechanism negotiation completes
01762          * successfully, we don't need the MIC.  See RFC 4178.
01763          */
01764 
01765         free_NegTokenResp(&resp);
01766         return (ret);
01767 }
01768 
01769 
01770 
01771 OM_uint32
01772 gss_init_sec_context_spnego(OM_uint32 *minor_status,
01773                             const gss_cred_id_t initiator_cred_handle,
01774                             gss_ctx_id_t *context_handle,
01775                             const gss_name_t target_name,
01776                             const gss_OID mech_type,
01777                             OM_uint32 req_flags,
01778                             OM_uint32 time_req,
01779                             const gss_channel_bindings_t input_chan_bindings,
01780                             const gss_buffer_t input_token,
01781                             gss_OID *actual_mech_type,
01782                             gss_buffer_t output_token,
01783                             OM_uint32 *ret_flags,
01784                             OM_uint32 *time_rec)
01785 {
01786         /* Dirty trick to suppress compiler warnings */
01787 
01788         /* Figure out whether we're starting over or processing a reply */
01789 
01790         if (input_token == GSS_C_NO_BUFFER || input_token->length == 0U)
01791                 return (spnego_initial(minor_status,
01792                                        initiator_cred_handle,
01793                                        context_handle,
01794                                        target_name,
01795                                        mech_type,
01796                                        req_flags,
01797                                        time_req,
01798                                        input_chan_bindings,
01799                                        input_token,
01800                                        actual_mech_type,
01801                                        output_token,
01802                                        ret_flags,
01803                                        time_rec));
01804         else
01805                 return (spnego_reply(minor_status,
01806                                      initiator_cred_handle,
01807                                      context_handle,
01808                                      target_name,
01809                                      mech_type,
01810                                      req_flags,
01811                                      time_req,
01812                                      input_chan_bindings,
01813                                      input_token,
01814                                      actual_mech_type,
01815                                      output_token,
01816                                      ret_flags,
01817                                      time_rec));
01818 }
01819 
01820 #endif /* GSSAPI */

Generated on Tue Apr 28 17:41:01 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha