spnego.c revision 6a1a8186afb298c87b3e5ae3fbbda95ea94f6bbd
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 2006-2009 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and/or distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
e35c1bb3ecd9a6597360b9160b397c8053af69bfDanny Mayer * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
e35c1bb3ecd9a6597360b9160b397c8053af69bfDanny Mayer * PERFORMANCE OF THIS SOFTWARE.
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence/* $Id: spnego.c,v 1.12 2009/07/21 06:53:09 marka Exp $ */
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * Portable SPNEGO implementation.
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * This is part of a portable implementation of the SPNEGO protocol
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * (RFCs 2478 and 4178). This implementation uses the RFC 4178 ASN.1
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * module but is not a full implementation of the RFC 4178 protocol;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * at the moment, we only support GSS-TSIG with Kerberos
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * authentication, so we only need enough of the SPNEGO protocol to
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * support that.
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * The files that make up this portable SPNEGO implementation are:
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * \li spnego.c (this file)
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * \li spnego.h (API SPNEGO exports to the rest of lib/dns)
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * \li spnego.asn1 (SPNEGO ASN.1 module)
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * \li spnego_asn1.c (routines generated from spngo.asn1)
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * \li spnego_asn1.pl (perl script to generate spnego_asn1.c)
f05a4bf2bfac3aaff0462560b2793cd99a85a297Mark Andrews * Everything but the functions exported in spnego.h is static, to
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * avoid possible conflicts with other libraries (particularly Heimdal,
f05a4bf2bfac3aaff0462560b2793cd99a85a297Mark Andrews * since much of this code comes from Heimdal by way of mod_auth_kerb).
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * spnego_asn1.c is shipped as part of lib/dns because generating it
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * requires both Perl and the Heimdal ASN.1 compiler. See
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * spnego_asn1.pl for further details. We've tried to eliminate all
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * compiler warnings from the generated code, but you may see a few
cb73e2bfacb60eed27a3e4940f6dbe0c0580fc18David Lawrence * when using a compiler version we haven't tested yet.
#ifdef GSSAPI
* but using this list (borrowed from gssapictx.c) gets rid of some
#include <config.h>
#include <stdlib.h>
#include <errno.h>
#include "dst_internal.h"
#include "spnego.h"
/* asn1_err.h */
/* Generated from ../../../lib/asn1/asn1_err.et */
typedef enum asn1_error_number {
#define __asn1_common_definitions__
typedef struct octet_string {
void *data;
} octet_string;
typedef char *general_string;
typedef char *utf8_string;
typedef struct oid {
unsigned *components;
} oid;
/* der.h */
} Der_class;
} Der_type;
static size_t
#include "spnego_asn1.c"
static unsigned char gss_krb5_mech_oid_bytes[] = {
sizeof(gss_krb5_mech_oid_bytes),
static unsigned char gss_mskrb5_mech_oid_bytes[] = {
sizeof(gss_mskrb5_mech_oid_bytes),
static unsigned char gss_spnego_mech_oid_bytes[] = {
sizeof(gss_spnego_mech_oid_bytes),
/* spnegokrb5_locl.h */
static OM_uint32
const gss_OID);
static OM_uint32
size_t *,
const gss_OID);
/* mod_auth_kerb.c */
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
len = *p++;
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
/* accept_sec_context.c */
static OM_uint32
unsigned char **outbuf,
return (GSS_S_FAILURE);
if (ret == 0) {
CONS,
&tmp);
if (ret == 0)
if (ret) {
return (GSS_S_FAILURE);
return (GSS_S_FAILURE);
return (GSS_S_FAILURE);
return (GSS_S_COMPLETE);
static OM_uint32
return (GSS_S_FAILURE);
if (ret)
return (ret);
return (GSS_S_BAD_MECH);
static OM_uint32
return (GSS_S_FAILURE);
return (GSS_S_FAILURE);
NULL);
if (ret) {
return (GSS_S_FAILURE);
return (GSS_S_FAILURE);
if (ret)
return (ret);
return (GSS_S_COMPLETE);
unsigned char *buf;
int found = 0;
int ret;
if (ret)
return (ret);
if (ret)
return (ret);
if (ret) {
return (GSS_S_DEFECTIVE_TOKEN);
sizeof(mechbuf),
&mech_len);
if (ret)
return (GSS_S_DEFECTIVE_TOKEN);
mech_len) == 0) {
mech_len) == 0) {
if (!found)
&ibuf,
&obuf,
return (major_status);
return (ret);
/* decapsulate.c */
static OM_uint32
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
p += len_len;
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
p += foo;
return (GSS_S_BAD_MECH);
return (GSS_S_BAD_MECH);
p += mech_len;
*str = p;
return (GSS_S_COMPLETE);
static OM_uint32
unsigned char **buf,
u_char *p;
mech);
if (ret) {
return (GSS_S_FAILURE);
*buf = p;
return (GSS_S_COMPLETE);
/* der_free.c */
/* der_get.c */
unsigned val = 0;
while (len--)
if (size)
int val = 0;
if (len > 0) {
val = (signed char)*p++;
while (--len)
if (size)
size_t v;
if (len <= 0)
return (ASN1_OVERRUN);
--len;
*val = v;
if (size)
size_t l;
unsigned tmp;
if (size)
if (len < v)
return (ASN1_OVERRUN);
if (size)
return (ENOMEM);
if (size)
return (ASN1_OVERRUN);
return (ENOMEM);
--len;
--len;
return (ASN1_OVERRUN);
if (size)
return (ASN1_OVERRUN);
if (size)
size_t l;
int thistag;
return (ASN1_BAD_ID);
return (ASN1_MISPLACED_FIELD);
return (ASN1_MISSING_FIELD);
if (size)
*size = l;
len -= l;
ret += l;
len -= l;
ret += l;
if (size)
len -= l;
ret += l;
len -= l;
ret += l;
len -= l;
ret += l;
if (size)
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
return (ASN1_OVERRUN);
len -= l;
ret += l;
if (size)
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
return (ASN1_OVERRUN);
len -= l;
ret += l;
if (size)
/* der_length.c */
static size_t
++ret;
} while (val);
return (ret);
static size_t
/* der_put.c */
unsigned char *base = p;
if (val) {
--len;
if (val != 0)
return (ASN1_OVERFLOW);
return (ASN1_OVERFLOW);
unsigned char *base = p;
if (val >= 0) {
return (ASN1_OVERFLOW);
len--;
} while (val);
return (ASN1_OVERFLOW);
len--;
return (ASN1_OVERFLOW);
len--;
} while (val);
return (ASN1_OVERFLOW);
len--;
return (ASN1_OVERFLOW);
*p = val;
size_t l;
return (ASN1_OVERFLOW);
unsigned char *base = p;
return (ASN1_OVERFLOW);
--len;
return (ASN1_OVERFLOW);
--len;
return (ASN1_OVERFLOW);
return (ASN1_OVERFLOW);
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
size_t l;
len -= l;
ret += l;
len -= l;
ret += l;
/* encapsulate.c */
static u_char *
return (NULL);
p += len_len;
static OM_uint32
unsigned char *buf,
u_char *p;
return (GSS_S_FAILURE);
if (p == NULL) {
return (GSS_S_FAILURE);
return (GSS_S_COMPLETE);
/* init_sec_context.c */
int ret;
return (ENOMEM);
if (ret)
return (ret);
static ssize_t
p += len_len;
p += foo;
*mech_ret = p;
return (mech_len);
static OM_uint32
int ret;
(void)mech_type;
if (ret) {
goto end;
time_rec);
goto end;
goto end;
if (ret == 0) {
len,
CONS,
&tmp);
if (ret == 0)
if (ret) {
goto end;
goto end;
end:
if (buf)
return (ret);
static OM_uint32
unsigned char *buf;
const u_char *p;
(void)mech_type;
if (mech_len < 0) {
time_rec));
&buf,
&buf_size,
if (ret)
return (ret);
return (GSS_S_BAD_MECH);
if (ret)
return (ret);
return (ASN1_OVERRUN);
if (ret) {
return (GSS_S_FAILURE);
return (GSS_S_BAD_MECH);
sizeof(oidbuf),
&oidlen);
oidlen) != 0) {
return GSS_S_BAD_MECH;
time_rec);
if (ret) {
return (ret);
return (ret);
time_rec));
time_rec));