/*
- * Copyright (c) 2010, JANET(UK)
+ * Copyright (c) 2011, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* SUCH DAMAGE.
*/
/*
- * Copyright 1993 by OpenVision Technologies, Inc.
+ * Portions Copyright 1993 by OpenVision Technologies, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * Utility routines for GSS tokens.
+ */
+
#include "gssapiP_eap.h"
+OM_uint32
+gssEapEncodeInnerTokens(OM_uint32 *minor,
+ gss_buffer_set_t extensions,
+ OM_uint32 *types,
+ gss_buffer_t buffer)
+{
+ OM_uint32 major, tmpMinor;
+ size_t required = 0, i;
+ unsigned char *p;
+
+ buffer->value = NULL;
+ buffer->length = 0;
+
+ if (extensions != GSS_C_NO_BUFFER_SET) {
+ for (i = 0; i < extensions->count; i++) {
+ required += 8 + extensions->elements[i].length;
+ }
+ }
+
+ /*
+ * We must always return a non-NULL token otherwise the calling state
+ * machine assumes we are finished. Hence care in case malloc(0) does
+ * return NULL.
+ */
+ buffer->value = GSSEAP_MALLOC(required ? required : 1);
+ if (buffer->value == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ buffer->length = required;
+ p = (unsigned char *)buffer->value;
+
+ if (extensions != GSS_C_NO_BUFFER_SET) {
+ for (i = 0; i < extensions->count; i++) {
+ gss_buffer_t extension = &extensions->elements[i];
+
+ assert((types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */
+
+ /*
+ * Extensions are encoded as type-length-value, where the upper
+ * bit of the type indicates criticality.
+ */
+ store_uint32_be(types[i], &p[0]);
+ store_uint32_be(extension->length, &p[4]);
+ memcpy(&p[8], extension->value, extension->length);
+
+ p += 8 + extension->length;
+ }
+ }
+
+ assert(p == (unsigned char *)buffer->value + required);
+ assert(buffer->value != NULL);
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gss_release_buffer(&tmpMinor, buffer);
+ }
+
+ return major;
+}
+
+OM_uint32
+gssEapDecodeInnerTokens(OM_uint32 *minor,
+ const gss_buffer_t buffer,
+ gss_buffer_set_t *pExtensions,
+ OM_uint32 **pTypes)
+{
+ OM_uint32 major, tmpMinor;
+ gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+ OM_uint32 *types = NULL;
+ unsigned char *p;
+ size_t remain;
+
+ *pExtensions = GSS_C_NO_BUFFER_SET;
+ *pTypes = NULL;
+
+ major = gss_create_empty_buffer_set(minor, &extensions);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (buffer->length == 0) {
+ major = GSS_S_COMPLETE;
+ goto cleanup;
+ }
+
+ p = (unsigned char *)buffer->value;
+ remain = buffer->length;
+
+ do {
+ OM_uint32 *ntypes;
+ gss_buffer_desc extension;
+
+ if (remain < 8) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_TOK_TRUNC;
+ goto cleanup;
+ }
+
+ ntypes = GSSEAP_REALLOC(types,
+ (extensions->count + 1) * sizeof(OM_uint32));
+ if (ntypes == NULL) {
+ major = GSS_S_FAILURE;
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+ types = ntypes;
+
+ types[extensions->count] = load_uint32_be(&p[0]);
+ extension.length = load_uint32_be(&p[4]);
+
+ if (remain < 8 + extension.length) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_TOK_TRUNC;
+ goto cleanup;
+ }
+ extension.value = &p[8];
+
+ major = gss_add_buffer_set_member(minor, &extension, &extensions);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ p += 8 + extension.length;
+ remain -= 8 + extension.length;
+ } while (remain != 0);
+
+cleanup:
+ if (GSS_ERROR(major)) {
+ gss_release_buffer_set(&tmpMinor, &extensions);
+ if (types != NULL)
+ GSSEAP_FREE(types);
+ } else {
+ *pExtensions = extensions;
+ *pTypes = types;
+ }
+
+ return major;
+}
+
/*
* $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
*/
der_length_size(size_t length)
{
if (length < (1<<7))
- return(1);
+ return 1;
else if (length < (1<<8))
- return(2);
+ return 2;
#if INT_MAX == 0x7fff
else
- return(3);
+ return 3;
#else
else if (length < (1<<16))
- return(3);
+ return 3;
else if (length < (1<<24))
- return(4);
+ return 4;
else
- return(5);
+ return 5;
#endif
}
(*bufsize)--;
if (sf & 0x80) {
if ((sf &= 0x7f) > ((*bufsize)-1))
- return(-1);
+ return -1;
if (sf > sizeof(int))
- return (-1);
+ return -1;
ret = 0;
for (; sf; sf--) {
ret = (ret<<8) + (*(*buf)++);
size_t
tokenSize(const gss_OID_desc *mech, size_t body_size)
{
+ assert(mech != GSS_C_NO_OID);
+
/* set body_size to sequence contents size */
body_size += 4 + (size_t) mech->length; /* NEED overflow check */
- return (1 + der_length_size(body_size) + body_size);
+ return 1 + der_length_size(body_size) + body_size;
}
/* fills in a buffer with the token header. The buffer is assumed to
*(*buf)++ = (unsigned char)mech->length;
memcpy(*buf, mech->elements, mech->length);
*buf += mech->length;
- if (tok_type != TOK_TYPE_NONE) {
- *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
- *(*buf)++ = (unsigned char)(tok_type & 0xff);
- }
+ assert(tok_type != TOK_TYPE_NONE);
+ *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
+ *(*buf)++ = (unsigned char)(tok_type & 0xff);
}
/*
* *body_size are left unmodified on error.
*/
-int
-verifyTokenHeader(
- const gss_OID_desc * mech,
- size_t *body_size,
- unsigned char **buf_in,
- size_t toksize_in,
- enum gss_eap_token_type tok_type)
+OM_uint32
+verifyTokenHeader(OM_uint32 *minor,
+ gss_OID mech,
+ size_t *body_size,
+ unsigned char **buf_in,
+ size_t toksize_in,
+ enum gss_eap_token_type *ret_tok_type)
{
unsigned char *buf = *buf_in;
ssize_t seqsize;
gss_OID_desc toid;
ssize_t toksize = (ssize_t)toksize_in;
- if (toksize -= 1 < 0)
- return ERANGE;
+ *minor = GSSEAP_BAD_TOK_HEADER;
+
+ if (ret_tok_type != NULL)
+ *ret_tok_type = TOK_TYPE_NONE;
+
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
if (*buf++ != 0x60)
- return EINVAL;
+ return GSS_S_DEFECTIVE_TOKEN;
seqsize = der_read_length(&buf, &toksize);
if (seqsize < 0)
- return ERANGE;
+ return GSS_S_DEFECTIVE_TOKEN;
if (seqsize != toksize)
- return ERANGE;
+ return GSS_S_DEFECTIVE_TOKEN;
- if (toksize -= 1 < 0)
- return ERANGE;
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
if (*buf++ != 0x06)
- return EINVAL;
+ return GSS_S_DEFECTIVE_TOKEN;
- if (toksize -= 1 < 0)
- return ERANGE;
+ if ((toksize -= 1) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
toid.length = *buf++;
- if (toksize -= toid.length < 0)
- return ERANGE;
+ if ((toksize -= toid.length) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
toid.elements = buf;
buf += toid.length;
- if (!oidEqual(&toid, mech))
- return EINVAL;
+ if (mech->elements == NULL) {
+ *mech = toid;
+ if (toid.length == 0)
+ return GSS_S_BAD_MECH;
+ } else if (!oidEqual(&toid, mech)) {
+ *minor = GSSEAP_WRONG_MECH;
+ return GSS_S_BAD_MECH;
+ }
- if (tok_type != TOK_TYPE_NONE) {
- if (toksize -= 2 < 0)
- return EINVAL;
+ if (ret_tok_type != NULL) {
+ if ((toksize -= 2) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
- if ((*buf++ != ((tok_type>>8) & 0xff)) ||
- (*buf++ != (tok_type & 0xff)))
- return EINVAL;
+ *ret_tok_type = load_uint16_be(buf);
+ buf += 2;
}
+
*buf_in = buf;
*body_size = toksize;
- return 0;
+ *minor = 0;
+ return GSS_S_COMPLETE;
}