MIT build fixes
[mech_eap.orig] / util_exts.c
index 906430c..46534d9 100644 (file)
  * SUCH DAMAGE.
  */
 
+/*
+ * Extension token support.
+ */
+
 #include "gssapiP_eap.h"
 
 static OM_uint32
 encodeExtensions(OM_uint32 *minor,
                  gss_buffer_set_t extensions,
                  OM_uint32 *types,
+                 gss_buffer_t buffer);
+
+static OM_uint32
+decodeExtensions(OM_uint32 *minor,
+                 const gss_buffer_t buffer,
+                 gss_buffer_set_t *pExtensions,
+                 OM_uint32 **pTypes);
+
+/*
+ * Initiator extensions
+ */
+static OM_uint32
+makeGssChannelBindings(OM_uint32 *minor,
+                       gss_cred_id_t cred,
+                       gss_ctx_id_t ctx,
+                       gss_channel_bindings_t chanBindings,
+                       gss_buffer_t outputToken)
+{
+    OM_uint32 major;
+    gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
+
+    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
+        buffer = chanBindings->application_data;
+
+    major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
+                       &buffer, NULL, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+verifyGssChannelBindings(OM_uint32 *minor,
+                         gss_cred_id_t cred,
+                         gss_ctx_id_t ctx,
+                         gss_channel_bindings_t chanBindings,
+                         gss_buffer_t inputToken)
+{
+    OM_uint32 major, tmpMinor;
+    gss_iov_buffer_desc iov[2];
+
+    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+    iov[0].buffer.length = 0;
+    iov[0].buffer.value = NULL;
+
+    iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
+    iov[1].buffer = *inputToken;
+
+    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+                                    iov, 2, TOK_TYPE_WRAP);
+    if (GSS_ERROR(major))
+        return GSS_S_BAD_BINDINGS;
+
+    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
+        !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
+        major = GSS_S_BAD_BINDINGS;
+        *minor = GSSEAP_BINDINGS_MISMATCH;
+    } else {
+        major = GSS_S_COMPLETE;
+    }
+
+    gss_release_buffer(&tmpMinor, &iov[0].buffer);
+
+    return major;
+}
+
+static struct gss_eap_extension_provider
+eapGssInitExtensions[] = {
+    {
+        EXT_TYPE_GSS_CHANNEL_BINDINGS,
+        1, /* critical */
+        1, /* required */
+        makeGssChannelBindings,
+        verifyGssChannelBindings
+    },
+};
+
+/*
+ * Acceptor extensions
+ */
+static OM_uint32
+makeReauthCreds(OM_uint32 *minor,
+                gss_cred_id_t cred,
+                gss_ctx_id_t ctx,
+                gss_channel_bindings_t chanBindings,
+                gss_buffer_t outputToken)
+{
+    OM_uint32 major = GSS_S_UNAVAILABLE;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+    /*
+     * If we're built with fast reauthentication enabled, then
+     * fabricate a ticket from the initiator to ourselves.
+     */
+    major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
+#endif
+
+    return major;
+}
+
+static OM_uint32
+verifyReauthCreds(OM_uint32 *minor,
+                  gss_cred_id_t cred,
+                  gss_ctx_id_t ctx,
+                  gss_channel_bindings_t chanBindings,
+                  gss_buffer_t inputToken)
+{
+    OM_uint32 major = GSS_S_UNAVAILABLE;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+    major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
+#endif
+
+    return major;
+}
+
+static struct gss_eap_extension_provider
+eapGssAcceptExtensions[] = {
+    {
+        EXT_TYPE_REAUTH_CREDS,
+        0, /* critical */
+        0, /* required */
+        makeReauthCreds,
+        verifyReauthCreds
+    },
+};
+
+OM_uint32
+makeExtensions(OM_uint32 *minor,
+               gss_cred_id_t cred,
+               gss_ctx_id_t ctx,
+               const struct gss_eap_extension_provider *exts,
+               size_t nexts,
+               gss_channel_bindings_t chanBindings,
+               gss_buffer_t buffer)
+{
+    OM_uint32 major, tmpMinor;
+    size_t i, j;
+    gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *types;
+
+    assert(buffer != GSS_C_NO_BUFFER);
+
+    buffer->length = 0;
+    buffer->value = NULL;
+
+    types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
+    if (types == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    for (i = 0, j = 0; i < nexts; i++) {
+        const struct gss_eap_extension_provider *ext = &exts[i];
+        gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
+
+        types[j] = ext->type;
+        if (ext->critical)
+            types[j] |= EXT_FLAG_CRITICAL;
+
+        major = ext->make(minor, cred, ctx, chanBindings, &extension);
+        if (GSS_ERROR(major)) {
+            if (ext->critical)
+                goto cleanup;
+            else
+                continue;
+        }
+
+        major = gss_add_buffer_set_member(minor, &extension, &extensions);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        j++;
+    }
+
+    assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
+
+    major = encodeExtensions(minor, extensions, types, buffer);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+cleanup:
+    gss_release_buffer_set(&tmpMinor, &extensions);
+    if (types != NULL)
+        GSSEAP_FREE(types);
+
+    return major;
+}
+
+OM_uint32
+gssEapMakeExtensions(OM_uint32 *minor,
+                     gss_cred_id_t cred,
+                     gss_ctx_id_t ctx,
+                     gss_channel_bindings_t chanBindings,
+                     gss_buffer_t buffer)
+{
+    size_t nexts;
+    const struct gss_eap_extension_provider *exts;
+
+    if (CTX_IS_INITIATOR(ctx)) {
+        exts = eapGssInitExtensions;
+        nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
+    } else {
+        exts = eapGssAcceptExtensions;
+        nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
+    }
+
+    return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
+}
+
+static OM_uint32
+verifyExtensions(OM_uint32 *minor,
+                 gss_cred_id_t cred,
+                 gss_ctx_id_t ctx,
+                 const struct gss_eap_extension_provider *exts,
+                 size_t nexts,
+                 gss_channel_bindings_t chanBindings,
+                 const gss_buffer_t buffer)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
+    OM_uint32 *types = NULL;
+    size_t i;
+
+    major = decodeExtensions(minor, buffer, &extensions, &types);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    for (i = 0; i < nexts; i++) {
+        const struct gss_eap_extension_provider *ext = &exts[i];
+        gss_buffer_t extension = GSS_C_NO_BUFFER;
+        size_t j;
+
+        for (j = 0; j < extensions->count; j++) {
+            if ((types[j] & EXT_TYPE_MASK) == ext->type) {
+                extension = &extensions->elements[j];
+                break;
+            }
+        }
+
+        if (extension != GSS_C_NO_BUFFER) {
+            /* Process extension and mark as verified */
+            major = ext->verify(minor, cred, ctx, chanBindings,
+                                &extensions->elements[j]);
+            if (GSS_ERROR(major))
+                goto cleanup;
+
+            types[j] |= EXT_FLAG_VERIFIED;
+        } else if (ext->required) {
+            /* Required extension missing */
+            major = GSS_S_UNAVAILABLE;
+            *minor = GSSEAP_MISSING_REQUIRED_EXT;
+            goto cleanup;
+        }
+    }
+
+    /* Check we processed all critical extensions */
+    for (i = 0; i < extensions->count; i++) {
+        if ((types[i] & EXT_FLAG_CRITICAL) &&
+            (types[i] & EXT_FLAG_VERIFIED) == 0) {
+            major = GSS_S_UNAVAILABLE;
+            *minor = GSSEAP_CRIT_EXT_UNAVAILABLE;
+            goto cleanup;
+        }
+    }
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    gss_release_buffer_set(&tmpMinor, &extensions);
+    if (types != NULL)
+        GSSEAP_FREE(types);
+
+    return major;
+}
+
+OM_uint32
+gssEapVerifyExtensions(OM_uint32 *minor,
+                       gss_cred_id_t cred,
+                       gss_ctx_id_t ctx,
+                       gss_channel_bindings_t chanBindings,
+                       const gss_buffer_t buffer)
+{
+    size_t nexts;
+    const struct gss_eap_extension_provider *exts;
+
+    if (CTX_IS_INITIATOR(ctx)) {
+        exts = eapGssAcceptExtensions;
+        nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
+    } else {
+        exts = eapGssInitExtensions;
+        nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
+    }
+
+    return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
+}
+
+static OM_uint32
+encodeExtensions(OM_uint32 *minor,
+                 gss_buffer_set_t extensions,
+                 OM_uint32 *types,
                  gss_buffer_t buffer)
 {
     OM_uint32 major, tmpMinor;
@@ -58,8 +366,8 @@ encodeExtensions(OM_uint32 *minor,
      */
     buffer->value = GSSEAP_MALLOC(required ? required : 1);
     if (buffer->value == NULL) {
-        *minor = ENOMEM;
         major = GSS_S_FAILURE;
+        *minor = ENOMEM;
         goto cleanup;
     }
 
@@ -87,6 +395,9 @@ encodeExtensions(OM_uint32 *minor,
     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);
@@ -128,14 +439,15 @@ decodeExtensions(OM_uint32 *minor,
 
         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) {
-            *minor = ENOMEM;
             major = GSS_S_FAILURE;
+            *minor = ENOMEM;
             goto cleanup;
         }
         types = ntypes;
@@ -145,6 +457,7 @@ decodeExtensions(OM_uint32 *minor,
 
         if (remain < 8 + extension.length) {
             major = GSS_S_DEFECTIVE_TOKEN;
+            *minor = GSSEAP_TOK_TRUNC;
             goto cleanup;
         }
         extension.value = &p[8];
@@ -169,139 +482,3 @@ cleanup:
 
     return major;
 }
-
-OM_uint32
-gssEapMakeExtensions(OM_uint32 *minor,
-                     gss_cred_id_t cred,
-                     gss_ctx_id_t ctx,
-                     const struct gss_eap_extension_provider *exts,
-                     size_t count,
-                     gss_channel_bindings_t chanBindings,
-                     gss_buffer_t buffer)
-{
-    OM_uint32 major, tmpMinor;
-    size_t i, j;
-    gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
-    OM_uint32 *types;
-
-    assert(buffer != GSS_C_NO_BUFFER);
-
-    buffer->length = 0;
-    buffer->value = NULL;
-
-    types = GSSEAP_CALLOC(count, sizeof(OM_uint32));
-    if (types == NULL) {
-        *minor = ENOMEM;
-        major = GSS_S_FAILURE;
-        goto cleanup;
-    }
-
-    for (i = 0, j = 0; i < count; i++) {
-        const struct gss_eap_extension_provider *ext = &exts[i];
-        gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
-
-        types[j] = ext->type;
-        if (ext->critical)
-            types[j] |= EXT_FLAG_CRITICAL;
-
-        major = ext->callback(minor, cred, ctx, chanBindings, &extension);
-        if (GSS_ERROR(major)) {
-            if (ext->critical)
-                continue;
-            else
-                goto cleanup;
-        }
-
-        major = gss_add_buffer_set_member(minor, &extension, &extensions);
-        if (GSS_ERROR(major))
-            goto cleanup;
-
-        j++;
-    }
-
-    assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
-
-    major = encodeExtensions(minor, extensions, types, buffer);
-    if (GSS_ERROR(major))
-        goto cleanup;
-
-cleanup:
-    gss_release_buffer_set(&tmpMinor, &extensions);
-    if (types != NULL)
-        GSSEAP_FREE(types);
-
-    return major;
-}
-
-OM_uint32
-gssEapVerifyExtensions(OM_uint32 *minor,
-                       gss_cred_id_t cred,
-                       gss_ctx_id_t ctx,
-                       const struct gss_eap_extension_provider *exts,
-                       size_t count,
-                       gss_channel_bindings_t chanBindings,
-                       const gss_buffer_t buffer)
-{
-    OM_uint32 major, tmpMinor;
-    gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
-    OM_uint32 *types = NULL;
-    size_t i;
-
-    major = decodeExtensions(minor, buffer, &extensions, &types);
-    if (GSS_ERROR(major))
-        goto cleanup;
-
-    for (i = 0; i < count; i++) {
-        const struct gss_eap_extension_provider *ext = &exts[i];
-        gss_buffer_t extension = GSS_C_NO_BUFFER;
-        size_t j;
-
-        for (j = 0; j < extensions->count; j++) {
-            if ((types[j] & EXT_TYPE_MASK) == ext->type) {
-                extension = &extensions->elements[j];
-                break;
-            }
-        }
-
-        if (extension != GSS_C_NO_BUFFER) {
-            /* Process extension and mark as verified */
-            major = ext->callback(minor, cred, ctx, chanBindings,
-                                  &extensions->elements[j]);
-            if (GSS_ERROR(major))
-                goto cleanup;
-
-            types[j] |= EXT_FLAG_VERIFIED;
-        } else if (ext->critical) {
-            /* Critical extension missing */
-            *minor = ENOENT;
-            major = GSS_S_UNAVAILABLE;
-            gssEapSaveStatusInfo(*minor,
-                                 "Missing critical GSS EAP extension %08x",
-                                 ext->type);
-            goto cleanup;
-        }
-    }
-
-    /* Check we processed all critical extensions */
-    for (i = 0; i < extensions->count; i++) {
-        if ((types[i] & EXT_FLAG_CRITICAL) &&
-            (types[i] & EXT_FLAG_VERIFIED) == 0) {
-            *minor = ENOSYS;
-            major = GSS_S_UNAVAILABLE;
-            gssEapSaveStatusInfo(*minor,
-                                 "Received unknown critical GSS EAP extension %08x",
-                                 (types[i] & EXT_TYPE_MASK));
-            goto cleanup;
-        }
-    }
-
-    *minor = 0;
-    major = GSS_S_COMPLETE;
-
-cleanup:
-    gss_release_buffer_set(&tmpMinor, &extensions);
-    if (types != NULL)
-        GSSEAP_FREE(types);
-
-    return major;
-}