NegoEx SPIs
authorLuke Howard <lukeh@padl.com>
Mon, 3 Oct 2011 23:22:14 +0000 (10:22 +1100)
committerLuke Howard <lukeh@padl.com>
Wed, 5 Oct 2011 01:39:22 +0000 (12:39 +1100)
12 files changed:
cyrus-sasl
mod_auth_kerb
moonshot/mech_eap/Makefile.am
moonshot/mech_eap/exchange_meta_data.c [new file with mode: 0644]
moonshot/mech_eap/gssapiP_eap.h
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/inquire_sec_context_by_oid.c
moonshot/mech_eap/mech_eap-noacceptor.exports
moonshot/mech_eap/mech_eap.exports
moonshot/mech_eap/query_mechanism_info.c [new file with mode: 0644]
moonshot/mech_eap/query_meta_data.c [new file with mode: 0644]
openssh

index ad4b5d3..05c7a77 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ad4b5d35ac842254bc6c897735fb932a457529e3
+Subproject commit 05c7a774bfb33da2514677cbabd804ebd409a0ec
index b07f536..5a97a7b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b07f536af4cd3a3f757e5e70e31051b0bb83cf17
+Subproject commit 5a97a7bec72eb87313c9b626321ea1d21f7fdab6
index 5f78a77..cb66fe8 100644 (file)
@@ -62,6 +62,7 @@ mech_eap_la_SOURCES =                         \
        display_status.c                        \
        duplicate_name.c                        \
        eap_mech.c                              \
+       exchange_meta_data.c                    \
        export_name.c                           \
        export_sec_context.c                    \
        get_mic.c                               \
@@ -82,6 +83,8 @@ mech_eap_la_SOURCES =                         \
        inquire_sec_context_by_oid.c            \
        process_context_token.c                 \
        pseudo_random.c                         \
+       query_mechanism_info.c                  \
+       query_meta_data.c                       \
        radsec_err.c                            \
        release_cred.c                          \
        release_name.c                          \
diff --git a/moonshot/mech_eap/exchange_meta_data.c b/moonshot/mech_eap/exchange_meta_data.c
new file mode 100644 (file)
index 0000000..5d56795
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32 GSSAPI_CALLCONV
+gssEapExchangeMetaData(OM_uint32 *minor,
+                       gss_const_OID mech GSSEAP_UNUSED,
+                       gss_cred_id_t cred GSSEAP_UNUSED,
+                       gss_ctx_id_t *ctx GSSEAP_UNUSED,
+                       const gss_name_t name GSSEAP_UNUSED,
+                       OM_uint32 req_flags GSSEAP_UNUSED,
+                       gss_const_buffer_t meta_data GSSEAP_UNUSED)
+{
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 GSSAPI_CALLCONV
+gss_exchange_meta_data(OM_uint32 *minor,
+                       gss_const_OID mech,
+                       gss_cred_id_t cred,
+                       gss_ctx_id_t *context_handle,
+                       const gss_name_t name,
+                       OM_uint32 req_flags,
+                       gss_const_buffer_t meta_data)
+{
+    gss_ctx_id_t ctx = *context_handle;
+    OM_uint32 major;
+
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+    if (*context_handle != GSS_C_NO_CONTEXT)
+        GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+    major = gssEapExchangeMetaData(minor, mech, cred, &ctx,
+                                   name, req_flags, meta_data);
+
+    if (*context_handle != GSS_C_NO_CONTEXT)
+        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+    else
+        *context_handle = ctx;
+
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+
+    return major;
+}
index 8b498e9..f42f7be 100644 (file)
@@ -342,6 +342,16 @@ gssEapDisplayStatus(OM_uint32 *minor,
 #define IS_RADIUS_ERROR(err)            ((err) >= ERROR_TABLE_BASE_rse && \
                                          (err) <= ERROR_TABLE_BASE_rse + 20)
 
+/* exchange_meta_data.c */
+OM_uint32 GSSAPI_CALLCONV
+gssEapExchangeMetaData(OM_uint32 *minor,
+                       gss_const_OID mech,
+                       gss_cred_id_t cred,
+                       gss_ctx_id_t *ctx,
+                       const gss_name_t name,
+                       OM_uint32 req_flags,
+                       gss_const_buffer_t meta_data);
+
 /* export_sec_context.c */
 OM_uint32
 gssEapExportSecContext(OM_uint32 *minor,
@@ -354,6 +364,13 @@ gssEapImportContext(OM_uint32 *minor,
                     gss_buffer_t token,
                     gss_ctx_id_t ctx);
 
+/* inquire_sec_context_by_oid.c */
+#define NEGOEX_INITIATOR_SALT      "gss-eap-negoex-initiator"
+#define NEGOEX_INITIATOR_SALT_LEN  (sizeof(NEGOEX_INITIATOR_SALT) - 1)
+
+#define NEGOEX_ACCEPTOR_SALT       "gss-eap-negoex-acceptor"
+#define NEGOEX_ACCEPTOR_SALT_LEN   (sizeof(NEGOEX_ACCEPTOR_SALT) - 1)
+
 /* pseudo_random.c */
 OM_uint32
 gssEapPseudoRandom(OM_uint32 *minor,
@@ -363,6 +380,16 @@ gssEapPseudoRandom(OM_uint32 *minor,
                    ssize_t desired_output_len,
                    gss_buffer_t prf_out);
 
+/* query_meta_data.c */
+OM_uint32
+gssEapQueryMetaData(OM_uint32 *minor,
+                    gss_const_OID mech GSSEAP_UNUSED,
+                    gss_cred_id_t cred,
+                    gss_ctx_id_t *context_handle,
+                    const gss_name_t name,
+                    OM_uint32 req_flags GSSEAP_UNUSED,
+                    gss_buffer_t meta_data);
+
 /* eap_mech.c */
 OM_uint32
 gssEapInitiatorInit(OM_uint32 *minor);
index dc5c70f..46e925e 100644 (file)
@@ -1048,8 +1048,6 @@ gss_init_sec_context(OM_uint32 *minor,
     output_token->length = 0;
     output_token->value = NULL;
 
-    GSSEAP_ASSERT(ctx == GSS_C_NO_CONTEXT || ctx->mechanismUsed != GSS_C_NO_OID);
-
     if (ctx == GSS_C_NO_CONTEXT) {
         if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
             *minor = GSSEAP_WRONG_SIZE;
index 67b2ec8..7435f2e 100644 (file)
 #include "gssapiP_eap.h"
 
 static OM_uint32
+addEnctypeOidToBufferSet(OM_uint32 *minor,
+                         krb5_enctype encryptionType,
+                         gss_buffer_set_t *dataSet)
+{
+    OM_uint32 major;
+    unsigned char oidBuf[16];
+    gss_OID_desc oid;
+    gss_buffer_desc buf;
+
+    oid.length = sizeof(oidBuf);
+    oid.elements = oidBuf;
+
+    major = composeOid(minor,
+                       "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
+                       10,
+                       encryptionType,
+                       &oid);
+    if (GSS_ERROR(major))
+        return major;
+
+    buf.length = oid.length;
+    buf.value = oid.elements;
+
+    major = gss_add_buffer_set_member(minor, &buf, dataSet);
+
+    return major;
+}
+
+static void
+zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet)
+{
+    OM_uint32 tmpMinor;
+    gss_buffer_set_t set = *dataSet;
+    size_t i;
+
+    if (set == GSS_C_NO_BUFFER_SET)
+        return;
+
+    for (i = 0; i <set->count; i++)
+        memset(set->elements[i].value, 0, set->elements[i].length);
+
+    gss_release_buffer_set(&tmpMinor, dataSet);
+}
+
+static OM_uint32
 inquireSessionKey(OM_uint32 *minor,
                   const gss_ctx_id_t ctx,
                   const gss_OID desired_object GSSEAP_UNUSED,
                   gss_buffer_set_t *dataSet)
 {
-    OM_uint32 major, tmpMinor;
-    unsigned char oidBuf[16];
+    OM_uint32 major;
     gss_buffer_desc buf;
-    gss_OID_desc oid;
+
+    if (ctx->encryptionType == ENCTYPE_NULL) {
+        major = GSS_S_UNAVAILABLE;
+        *minor = GSSEAP_KEY_UNAVAILABLE;
+        goto cleanup;
+    }
 
     buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
     buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
@@ -54,21 +103,69 @@ inquireSessionKey(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
-    oid.length = sizeof(oidBuf);
-    oid.elements = oidBuf;
+    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
+    if (GSS_ERROR(major))
+        goto cleanup;
 
-    major = composeOid(minor,
-                       "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
-                       10,
-                       ctx->encryptionType,
-                       &oid);
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
     if (GSS_ERROR(major))
+        zeroAndReleaseBufferSet(dataSet);
+
+    return major;
+}
+
+static OM_uint32
+inquireNegoExKey(OM_uint32 *minor,
+                  const gss_ctx_id_t ctx,
+                  const gss_OID desired_object,
+                  gss_buffer_set_t *dataSet)
+{
+    OM_uint32 major, tmpMinor;
+    int bInitiatorKey;
+    gss_buffer_desc salt;
+    gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
+    size_t keySize;
+
+    bInitiatorKey = CTX_IS_INITIATOR(ctx);
+
+    if (ctx->encryptionType == ENCTYPE_NULL) {
+        major = GSS_S_UNAVAILABLE;
+        *minor = GSSEAP_KEY_UNAVAILABLE;
         goto cleanup;
+    }
 
-    buf.length = oid.length;
-    buf.value = oid.elements;
+    /*
+     * If the caller supplied the verify key OID, then we need the acceptor
+     * key if we are the initiator, and vice versa.
+     */
+    if (desired_object->length == 11 &&
+        memcmp(desired_object->elements,
+               "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
+        bInitiatorKey ^= 1;
+
+    if (bInitiatorKey) {
+        salt.length = NEGOEX_INITIATOR_SALT_LEN;
+        salt.value  = NEGOEX_INITIATOR_SALT;
+    } else {
+        salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
+        salt.value  = NEGOEX_ACCEPTOR_SALT;
+    }
 
-    major = gss_add_buffer_set_member(minor, &buf, dataSet);
+    keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
+
+    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
+                               keySize, &key);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gss_add_buffer_set_member(minor, &key, dataSet);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
     if (GSS_ERROR(major))
         goto cleanup;
 
@@ -76,13 +173,12 @@ inquireSessionKey(OM_uint32 *minor,
     *minor = 0;
 
 cleanup:
-    if (GSS_ERROR(major) && *dataSet != GSS_C_NO_BUFFER_SET) {
-        gss_buffer_set_t set = *dataSet;
-
-        if (set->count != 0)
-            memset(set->elements[0].value, 0, set->elements[0].length);
-        gss_release_buffer_set(&tmpMinor, dataSet);
+    if (key.value != NULL) {
+        memset(key.value, 0, key.length);
+        gss_release_buffer(&tmpMinor, &key);
     }
+    if (GSS_ERROR(major))
+        zeroAndReleaseBufferSet(dataSet);
 
     return major;
 }
@@ -102,6 +198,16 @@ static struct {
         { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
         gssEapExportLucidSecContext
     },
+    {
+        /* GSS_C_INQ_NEGOEX_KEY */
+        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
+        inquireNegoExKey
+    },
+    {
+        /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
+        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
+        inquireNegoExKey
+    },
 };
 
 OM_uint32 GSSAPI_CALLCONV
@@ -117,11 +223,13 @@ gss_inquire_sec_context_by_oid(OM_uint32 *minor,
 
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
+#if 0
     if (!CTX_IS_ESTABLISHED(ctx)) {
         *minor = GSSEAP_CONTEXT_INCOMPLETE;
         major = GSS_S_NO_CONTEXT;
         goto cleanup;
     }
+#endif
 
     major = GSS_S_UNAVAILABLE;
     *minor = GSSEAP_BAD_CONTEXT_OPTION;
@@ -134,7 +242,6 @@ gss_inquire_sec_context_by_oid(OM_uint32 *minor,
         }
     }
 
-cleanup:
     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
 
     return major;
index 4ecbc52..f00df8a 100644 (file)
@@ -9,6 +9,7 @@ gss_display_name
 gss_display_name_ext
 gss_display_status
 gss_duplicate_name
+gss_exchange_meta_data
 gss_export_name
 gss_export_sec_context
 gss_get_mic
@@ -28,6 +29,8 @@ gss_inquire_saslname_for_mech
 gss_inquire_sec_context_by_oid
 gss_process_context_token
 gss_pseudo_random
+gss_query_mechanism_info
+gss_query_meta_data
 gss_release_cred
 gss_release_name
 gss_internal_release_oid
index 10c7f81..6a17a17 100644 (file)
@@ -11,6 +11,7 @@ gss_display_name
 gss_display_name_ext
 gss_display_status
 gss_duplicate_name
+gss_exchange_meta_data
 gss_export_name
 gss_export_name_composite
 gss_export_sec_context
@@ -34,6 +35,8 @@ gss_inquire_sec_context_by_oid
 gss_map_name_to_any
 gss_process_context_token
 gss_pseudo_random
+gss_query_mechanism_info
+gss_query_meta_data
 gss_release_any_name_mapping
 gss_release_cred
 gss_release_name
diff --git a/moonshot/mech_eap/query_mechanism_info.c b/moonshot/mech_eap/query_mechanism_info.c
new file mode 100644 (file)
index 0000000..3971ed4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32 GSSAPI_CALLCONV
+gss_query_mechanism_info(OM_uint32 *minor,
+                         gss_const_OID mech_oid,
+                         unsigned char auth_scheme[16])
+{
+    OM_uint32 major;
+    krb5_enctype enctype;
+
+    major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype);
+    if (GSS_ERROR(major))
+        return major;
+
+    /* the enctype is encoded in the increasing part of the GUID */
+    memcpy(auth_scheme,
+           "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16);
+
+    auth_scheme[3] = (unsigned char)enctype;
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/moonshot/mech_eap/query_meta_data.c b/moonshot/mech_eap/query_meta_data.c
new file mode 100644 (file)
index 0000000..ad3a6ca
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *
+ */
+
+#include "gssapiP_eap.h"
+
+OM_uint32
+gssEapQueryMetaData(OM_uint32 *minor,
+                    gss_const_OID mech GSSEAP_UNUSED,
+                    gss_cred_id_t cred,
+                    gss_ctx_id_t *context_handle,
+                    const gss_name_t name,
+                    OM_uint32 req_flags GSSEAP_UNUSED,
+                    gss_buffer_t meta_data)
+{
+    OM_uint32 major;
+    int isInitiator = (name != GSS_C_NO_NAME);
+    gss_ctx_id_t ctx = *context_handle;
+
+    meta_data->length = 0;
+    meta_data->value = NULL;
+
+    if (ctx == GSS_C_NO_CONTEXT) {
+        major = gssEapAllocContext(minor, &ctx);
+        if (GSS_ERROR(major))
+            return major;
+
+        if (isInitiator)
+            ctx->flags |= CTX_FLAG_INITIATOR;
+    }
+
+    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
+        if (isInitiator) {
+            major = gssEapResolveInitiatorCred(minor, cred,
+                                               name, &ctx->cred);
+        } else {
+            major = gssEapAcquireCred(minor,
+                                      GSS_C_NO_NAME,
+                                      GSS_C_INDEFINITE,
+                                      GSS_C_NO_OID_SET,
+                                      GSS_C_ACCEPT,
+                                      &ctx->cred,
+                                      NULL,
+                                      NULL);
+        }
+    }
+
+    if (*context_handle == GSS_C_NO_CONTEXT)
+        *context_handle = ctx;
+
+    return major;
+}
+
+OM_uint32 GSSAPI_CALLCONV
+gss_query_meta_data(OM_uint32 *minor,
+                    gss_const_OID mech,
+                    gss_cred_id_t cred,
+                    gss_ctx_id_t *context_handle,
+                    const gss_name_t name,
+                    OM_uint32 req_flags,
+                    gss_buffer_t meta_data)
+{
+    gss_ctx_id_t ctx = *context_handle;
+    OM_uint32 major;
+
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_LOCK(&cred->mutex);
+
+    if (*context_handle != GSS_C_NO_CONTEXT)
+        GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+    major = gssEapQueryMetaData(minor, mech, cred, &ctx,
+                                name, req_flags, meta_data);
+
+    if (*context_handle != GSS_C_NO_CONTEXT)
+        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+    else
+        *context_handle = ctx;
+
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+
+    return major;
+}
diff --git a/openssh b/openssh
index ac0ba1f..afca9d2 160000 (submodule)
--- a/openssh
+++ b/openssh
@@ -1 +1 @@
-Subproject commit ac0ba1f390586dd0300f0a036ce30952b1dd5def
+Subproject commit afca9d259be1d594e282f9a80714e4be12fea16e