#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,
types[extensions->count] = load_uint32_be(&p[0]);
extension.length = load_uint32_be(&p[4]);
- if (remain < 8 + extension.length) {
+ if (remain < ITOK_HEADER_LENGTH + extension.length) {
major = GSS_S_DEFECTIVE_TOKEN;
*minor = GSSEAP_TOK_TRUNC;
goto cleanup;
if (GSS_ERROR(major))
goto cleanup;
- p += 8 + extension.length;
- remain -= 8 + extension.length;
+ p += ITOK_HEADER_LENGTH + extension.length;
+ remain -= ITOK_HEADER_LENGTH + extension.length;
} while (remain != 0);
cleanup:
}
/*
+ * Add some data to the initiator/acceptor conversation.
+ */
+static OM_uint32
+recordTokens(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t tokens,
+ size_t tokensCount)
+{
+ unsigned char *buf;
+ size_t i, size, offset;
+
+ size = ctx->conversation.length;
+
+ for (i = 0; i < tokensCount; i++)
+ size += tokens[i].length;
+
+ buf = GSSEAP_REALLOC(ctx->conversation.value, size);
+ if (buf == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ offset = ctx->conversation.length;
+
+ ctx->conversation.length = size;
+ ctx->conversation.value = buf;
+
+ for (i = 0; i < tokensCount; i++) {
+ memcpy(buf + offset, tokens[i].value, tokens[i].length);
+ offset += tokens[i].length;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Record the context token header.
+ */
+OM_uint32
+gssEapRecordContextTokenHeader(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ enum gss_eap_token_type tokType)
+{
+ unsigned char wireOidHeader[2], wireTokType[2];
+ gss_buffer_desc buffers[3];
+
+ assert(ctx->mechanismUsed != GSS_C_NO_OID);
+
+ wireOidHeader[0] = 0x06;
+ wireOidHeader[1] = ctx->mechanismUsed->length;
+ buffers[0].length = sizeof(wireOidHeader);
+ buffers[0].value = wireOidHeader;
+
+ buffers[1].length = ctx->mechanismUsed->length;
+ buffers[1].value = ctx->mechanismUsed->elements;
+
+ store_uint16_be(tokType, wireTokType);
+ buffers[2].length = sizeof(wireTokType);
+ buffers[2].value = wireTokType;
+
+ return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
+}
+
+/*
+ * Record an inner context token.
+ */
+OM_uint32
+gssEapRecordInnerContextToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t innerToken,
+ OM_uint32 itokType)
+{
+ gss_buffer_desc buffers[2];
+ unsigned char itokHeader[ITOK_HEADER_LENGTH];
+
+ assert(innerToken != GSS_C_NO_BUFFER);
+
+ store_uint32_be(itokType, &itokHeader[0]);
+ store_uint32_be(innerToken->length, &itokHeader[4]);
+ buffers[0].length = sizeof(itokHeader);
+ buffers[0].value = itokHeader;
+
+ buffers[1] = *innerToken;
+
+ return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
+}
+
+OM_uint32
+gssEapVerifyContextToken(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t inputToken,
+ enum gss_eap_token_type tokType,
+ gss_buffer_t innerInputToken)
+{
+ OM_uint32 major;
+ size_t bodySize;
+ unsigned char *p = (unsigned char *)inputToken->value;
+ gss_OID_desc oidBuf;
+ gss_OID oid;
+ enum gss_eap_token_type actualTokType;
+ gss_buffer_desc tokenBuf;
+
+ if (ctx->mechanismUsed != GSS_C_NO_OID) {
+ oid = ctx->mechanismUsed;
+ } else {
+ oidBuf.elements = NULL;
+ oidBuf.length = 0;
+ oid = &oidBuf;
+ }
+
+ major = verifyTokenHeader(minor, oid, &bodySize, &p,
+ inputToken->length, &actualTokType);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (actualTokType != tokType) {
+ *minor = GSSEAP_WRONG_TOK_ID;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (ctx->mechanismUsed == GSS_C_NO_OID) {
+ major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ innerInputToken->length = bodySize;
+ innerInputToken->value = p;
+
+ /*
+ * Add OID, tokenType, body to conversation; variable length
+ * header omitted. A better API to verifyTokenHeader would
+ * avoid this ugly pointer arithmetic. XXX FIXME
+ */
+ tokenBuf.value = p - (2 + oid->length + 2);
+ tokenBuf.length = 2 + oid->length + 2 + bodySize;
+
+ major = recordTokens(minor, ctx, &tokenBuf, 1);
+ if (GSS_ERROR(major))
+ return major;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapEncodeSupportedExts(OM_uint32 *minor,
+ OM_uint32 *types,
+ size_t typesCount,
+ gss_buffer_t outputToken)
+{
+ size_t i;
+ unsigned char *p;
+
+ outputToken->value = GSSEAP_MALLOC(4 * typesCount);
+ if (outputToken->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ p = (unsigned char *)outputToken->value;
+
+ outputToken->length = 4 * typesCount;
+
+ for (i = 0; i < typesCount; i++) {
+ store_uint32_be(types[i], p);
+ p += 4;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapProcessSupportedExts(OM_uint32 *minor,
+ gss_buffer_t inputToken,
+ struct gss_eap_itok_map *map,
+ size_t mapCount,
+ OM_uint32 *flags)
+{
+ size_t i;
+ unsigned char *p;
+
+ if ((inputToken->length % 4) != 0) {
+ *minor = GSSEAP_TOK_TRUNC;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ p = (unsigned char *)inputToken->value;
+
+ for (i = 0; i < inputToken->length / 4; i++) {
+ OM_uint32 type = load_uint32_be(p);
+ size_t j;
+
+ for (j = 0; j < mapCount; j++) {
+ if (map->type == type) {
+ *flags |= map->flag;
+ break;
+ }
+ }
+
+ p += 4;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
* $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
*/
/* returns the length of a token, given the mech oid and the body size */
size_t
-tokenSize(const gss_OID_desc *mech, size_t body_size)
+tokenSize(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;
}
void
makeTokenHeader(
- const gss_OID_desc *mech,
size_t body_size,
- unsigned char **buf,
- enum gss_eap_token_type tok_type)
+ unsigned char **buf)
{
*(*buf)++ = 0x60;
- der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
- *(*buf)++ = 0x06;
- *(*buf)++ = (unsigned char)mech->length;
- memcpy(*buf, mech->elements, mech->length);
- *buf += mech->length;
- assert(tok_type != TOK_TYPE_NONE);
- *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
- *(*buf)++ = (unsigned char)(tok_type & 0xff);
+ der_write_length(buf, body_size);
}
/*