Merge branch 'master' into tlv-mic
[moonshot.git] / mech_eap / util_token.c
index 5231ae2..5e69b26 100644 (file)
@@ -30,7 +30,7 @@
  * 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,
 
 #include "gssapiP_eap.h"
 
+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 < ITOK_HEADER_LENGTH + 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      += ITOK_HEADER_LENGTH + extension.length;
+        remain -= ITOK_HEADER_LENGTH + 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;
+}
+
+/*
+ * 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 $
  */
@@ -162,10 +448,8 @@ der_read_length(unsigned char **buf, ssize_t *bufsize)
 /* 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)
 {
-    /* 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;
 }
 
@@ -174,20 +458,11 @@ tokenSize(const gss_OID_desc *mech, size_t 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);
 }
 
 /*