Merge in workaround for broken Kerberos 10.x gssapi.h origin/master
authorDan Breslau <dbreslau@painless-security.com>
Tue, 1 Aug 2017 18:20:48 +0000 (14:20 -0400)
committerDan Breslau <dbreslau@painless-security.com>
Tue, 1 Aug 2017 18:20:48 +0000 (14:20 -0400)
12 files changed:
configure.ac
mech_eap/accept_sec_context.c
mech_eap/eap_mech.c
mech_eap/get_mic.c
mech_eap/init_sec_context.c
mech_eap/util.h
mech_eap/util_attr.cpp
mech_eap/util_context.c
mech_eap/util_krb.c
mech_eap/util_name.c
mech_eap/util_shib.cpp
mech_eap/verify_mic.c

index a58e724..6134e8d 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ([2.61])
-AC_INIT([mech_eap], [0.9.5], [bugs@project-moonshot.org])
+AC_INIT([mech_eap], [1.0.0], [bugs@project-moonshot.org])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
 
index c284e8b..b594af0 100644 (file)
@@ -688,6 +688,9 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
     krb5_data data;
     krb5_checksum cksum;
     krb5_boolean valid = FALSE;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto;
+#endif
 
     if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
         chanBindings->application_data.length == 0)
@@ -701,9 +704,29 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
 
     KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
 
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, 0, &krbCrypto);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
+    }
+
+    code = krb5_verify_checksum(krbContext, krbCrypto,
+                                KEY_USAGE_GSSEAP_CHBIND_MIC,
+                                data.data, data.length, &cksum);
+    if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+        code = 0;
+        valid = FALSE;
+    } else if (code == 0) {
+        valid = TRUE;
+    }
+
+    krb5_crypto_destroy(krbContext, krbCrypto);
+#else
     code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
                                   KEY_USAGE_GSSEAP_CHBIND_MIC,
                                   &data, &cksum, &valid);
+#endif /* HAVE_HEIMDAL_VERSION */
     if (code != 0) {
         *minor = code;
         return GSS_S_FAILURE;
index c88ecf6..403e2f8 100644 (file)
@@ -205,6 +205,7 @@ gssEapInitiatorInit(OM_uint32 *minor)
 void
 gssEapFinalize(void)
 {
+    wpa_printf(MSG_INFO, "### gssEapFinalize()");
     eap_peer_unregister_methods();
 }
 
index 08dda7d..9a7bfc7 100644 (file)
 
 #include "gssapiP_eap.h"
 
-OM_uint32 GSSAPI_CALLCONV
-gss_get_mic_iov(OM_uint32 *minor,
-                gss_ctx_id_t ctx,
-                gss_qop_t qop_req,
-                gss_iov_buffer_desc *iov,
-                int iov_count)
+static OM_uint32
+gssEapGetMIC(OM_uint32 *minor,
+             gss_ctx_id_t ctx,
+             gss_qop_t qop_req,
+             gss_iov_buffer_desc *iov,
+             int iov_count)
 {
     OM_uint32 major;
 
@@ -101,9 +101,19 @@ gss_get_mic(OM_uint32 *minor,
     iov[1].buffer.value = NULL;
     iov[1].buffer.length = 0;
 
-    major = gss_get_mic_iov(minor, (gss_ctx_id_t)ctx, qop_req, iov, 2);
+    major = gssEapGetMIC(minor, (gss_ctx_id_t)ctx, qop_req, iov, 2);
     if (major == GSS_S_COMPLETE)
         *message_token = iov[1].buffer;
 
     return major;
 }
+
+OM_uint32 GSSAPI_CALLCONV
+gss_get_mic_iov(OM_uint32 *minor,
+                gss_ctx_id_t ctx,
+                gss_qop_t qop_req,
+                gss_iov_buffer_desc *iov,
+                int iov_count)
+{
+    return gssEapGetMIC(minor, ctx, qop_req, iov, iov_count);
+}
index 37bd3d0..7a2fb46 100644 (file)
@@ -40,7 +40,9 @@
 #include "util_radius.h"
 #include "utils/radius_utils.h"
 #include "openssl/err.h"
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
 #include "libmoonshot.h"
+#endif
 
 /* methods allowed for phase1 authentication*/
 static const struct eap_method_type allowed_eap_method_types[] = {
@@ -361,6 +363,7 @@ peerProcessChbindResponse(void *context, int code, int nsid,
     } /* else log failures? */
 }
 
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
 static int cert_to_byte_array(X509 *cert, unsigned char **bytes)
 {
        unsigned char *buf;
@@ -407,7 +410,6 @@ static int sha256(unsigned char *bytes, int len, unsigned char *hash)
        return hash_len;
 }
 
-
 static int peerValidateServerCert(int ok_so_far, X509* cert, void *ca_ctx)
 {
     char                 *realm = NULL;
@@ -444,7 +446,7 @@ static int peerValidateServerCert(int ok_so_far, X509* cert, void *ca_ctx)
     wpa_printf(MSG_INFO, "peerValidateServerCert: Returning %d\n", ok_so_far);
     return ok_so_far;
 }
-
+#endif
 
 static OM_uint32
 peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
@@ -554,7 +556,9 @@ peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
         eapPeerConfig->private_key_passwd = (char *)cred->password.value;
     }
 
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
     eapPeerConfig->server_cert_cb = peerValidateServerCert;
+#endif
     eapPeerConfig->server_cert_ctx = eapPeerConfig;
 
     *minor = 0;
@@ -1102,6 +1106,9 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
     krb5_data data;
     krb5_checksum cksum;
     gss_buffer_desc cksumBuffer;
+#ifdef HAVE_HEIMDAL_VERSION
+    krb5_crypto krbCrypto;
+#endif
 
     if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
         chanBindings->application_data.length == 0)
@@ -1113,10 +1120,25 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
 
     gssBufferToKrbData(&chanBindings->application_data, &data);
 
+#ifdef HAVE_HEIMDAL_VERSION
+    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, 0, &krbCrypto);
+    if (code != 0) {
+        *minor = code;
+        return GSS_S_FAILURE;
+    }
+
+    code = krb5_create_checksum(krbContext, krbCrypto,
+                                KEY_USAGE_GSSEAP_CHBIND_MIC,
+                                ctx->checksumType,
+                                data.data, data.length,
+                                &cksum);
+    krb5_crypto_destroy(krbContext, krbCrypto);
+#else
     code = krb5_c_make_checksum(krbContext, ctx->checksumType,
                                 &ctx->rfc3961Key,
                                 KEY_USAGE_GSSEAP_CHBIND_MIC,
                                 &data, &cksum);
+#endif /* HAVE_HEIMDAL_VERSION */
     if (code != 0) {
         *minor = code;
         return GSS_S_FAILURE;
@@ -1127,14 +1149,14 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
 
     major = duplicateBuffer(minor, &cksumBuffer, outputToken);
     if (GSS_ERROR(major)) {
-        krb5_free_checksum_contents(krbContext, &cksum);
+        KRB_CHECKSUM_FREE(krbContext, &cksum);
         return major;
     }
 
     *minor = 0;
     *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 
-    krb5_free_checksum_contents(krbContext, &cksum);
+    KRB_CHECKSUM_FREE(krbContext, &cksum);
 
     return GSS_S_CONTINUE_NEEDED;
 }
index 588af67..9028257 100644 (file)
@@ -377,6 +377,8 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
 
 #ifdef HAVE_HEIMDAL_VERSION
 
+#include <der.h>
+
 #define KRB_TIME_FOREVER        ((time_t)~0L)
 
 #define KRB_KEY_TYPE(key)       ((key)->keytype)
@@ -405,6 +407,11 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
         (cksum)->checksum.data = (d)->value;        \
     } while (0)
 
+#define KRB_CHECKSUM_FREE(ctx, cksum)          do { \
+        der_free_octet_string(&(cksum)->checksum);  \
+        memset((cksum), 0, sizeof(*(cksum)));       \
+    } while (0)
+                                    
 #else
 
 #define KRB_TIME_FOREVER        KRB5_INT32_MAX
@@ -441,6 +448,8 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
         (cksum)->contents = (d)->value;             \
     } while (0)
 
+#define KRB_CHECKSUM_FREE(ctx, cksum) krb5_free_checksum_contents((ctx), (cksum))
+
 #endif /* HAVE_HEIMDAL_VERSION */
 
 #define KRB_KEY_INIT(key)       do {        \
index beb283c..1931efe 100644 (file)
@@ -64,9 +64,14 @@ GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal)
     gssEapLocalAttrProviderInit(&minor);
 #endif
 #ifdef HAVE_OPENSAML
+    wpa_printf(MSG_INFO, "### gssEapAttrProvidersInitInternal(): Calling gssEapSamlAttrProvidersInit()");
     major = gssEapSamlAttrProvidersInit(&minor);
-    if (GSS_ERROR(major))
+    if (GSS_ERROR(major)) {
+        wpa_printf(MSG_ERROR, "### gssEapAttrProvidersInitInternal(): Error returned from gssEapSamlAttrProvidersInit; major code is %08X; minor is %08X", major, minor);
         goto cleanup;
+    }
+#else
+    wpa_printf(MSG_INFO, "### gssEapAttrProvidersInitInternal(): Don't have OpenSAML; not calling gssEapSamlAttrProvidersInit()");
 #endif
 
 cleanup:
@@ -74,6 +79,7 @@ cleanup:
     GSSEAP_ASSERT(major == GSS_S_COMPLETE);
 #endif
 
+    wpa_printf(MSG_INFO, "### gssEapAttrProvidersInitInternal(): Setting gssEapAttrProvidersInitStatus to %08X", major);
     gssEapAttrProvidersInitStatus = major;
 
     GSSEAP_ONCE_LEAVE;
@@ -90,16 +96,25 @@ gssEapAttrProvidersInit(OM_uint32 *minor)
     return gssEapAttrProvidersInitStatus;
 }
 
+
 namespace {
+
     class finalize_class {
     public:
+
+        finalize_class() {
+            wpa_printf(MSG_INFO, "### finalize_class::finalize_class(): Constructing");
+        }
+
       ~finalize_class()
            {
                OM_uint32 minor = 0;
+
+        wpa_printf(MSG_INFO, "### ~finalize_class::~finalize_class() : initStatus=%08x", gssEapAttrProvidersInitStatus);
+
                if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
-#ifdef HAVE_SHIBRESOLVER
-                   gssEapLocalAttrProviderFinalize(&minor);
-#endif
+            wpa_printf(MSG_INFO, "### ~finalize_class::~finalize_class() : really finalizing");
+
 #ifdef HAVE_OPENSAML
                    gssEapSamlAttrProvidersFinalize(&minor);
 #endif
index 039cfdb..b7a50c6 100644 (file)
@@ -353,8 +353,13 @@ gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
     } else {
         size_t checksumSize;
 
+#ifdef HAVE_HEIMDAL_VERSION
+        code = krb5_checksumsize(krbContext, ctx->checksumType,
+                                 &checksumSize);
+#else
         code = krb5_c_checksum_length(krbContext, ctx->checksumType,
                                       &checksumSize);
+#endif
         if (code != 0)
             goto cleanup;
 
index 2a3e970..f629a32 100644 (file)
@@ -329,7 +329,7 @@ rfc3961ChecksumTypeForKey(OM_uint32 *minor,
 
     *cksumtype = KRB_CHECKSUM_TYPE(&cksum);
 
-    krb5_free_checksum_contents(krbContext, &cksum);
+    KRB_CHECKSUM_FREE(krbContext, &cksum);
 #endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
 
 #ifdef HAVE_HEIMDAL_VERSION
@@ -480,6 +480,7 @@ krbEnctypeToString(
     return 0;
 }
 
+#ifdef GSSEAP_ENABLE_REAUTH
 krb5_error_code
 krbMakeAuthDataKdcIssued(krb5_context context,
                          const krb5_keyblock *key,
@@ -675,3 +676,4 @@ cleanup:
     return code;
 #endif /* HAVE_HEIMDAL_VERSION */
 }
+#endif /* GSSEAP_ENABLE_REAUTH */
index 7a2e60b..b85565c 100644 (file)
@@ -206,8 +206,13 @@ importServiceName(OM_uint32 *minor,
         *minor = GSSEAP_BAD_SERVICE_NAME;
     }
 
-    if (realm != NULL)
+    if (realm != NULL) {
+#ifdef HAVE_HEIMDAL_VERSION
+        krb5_xfree(realm);
+#else
         krb5_free_default_realm(krbContext, realm);
+#endif
+    }
     GSSEAP_FREE(service);
 
     return major;
index 7b62484..4ba70e0 100644 (file)
@@ -78,6 +78,58 @@ using namespace opensaml;
 using namespace xercesc;
 #endif
 
+
+namespace {
+
+
+    class ShibFinalizer {
+    public:
+
+        static bool isShibInitialized() {return shibInitialized;}
+        static void createSingleton();
+
+    private:
+        ShibFinalizer(): is_extra(false) {
+            if (shibInitialized) {
+                // This should never, ever happen. Initialization is (supposed to be)
+                // funneled through a single thread, so there should be no race
+                // conditions here. And only this class sets this flag, and there's
+                // only a single instance of this class.
+                wpa_printf(MSG_ERROR, "### ShibFinalizer::ShibFinalizer(): Attempt to construct an extraneous instance!");
+                is_extra = true;
+            }
+            else {
+                wpa_printf(MSG_INFO, "### ShibFinalizer::ShibFinalizer(): Constructing");
+                shibInitialized = true;
+            }
+        }
+
+        ~ShibFinalizer() {
+            if (!is_extra) {
+                wpa_printf(MSG_INFO, "### ShibFinalizer::~ShibFinalizer(): Destructing");
+                gss_eap_shib_attr_provider::finalize();
+                shibInitialized = false;
+            }
+            else {
+                wpa_printf(MSG_INFO, "### ShibFinalizer::~ShibFinalizer(): This was an extraneous instance; not destructing anything.");
+            }
+        }
+
+        bool is_extra;
+        static bool shibInitialized;
+    };
+}
+
+
+bool ShibFinalizer::shibInitialized = false;
+
+void ShibFinalizer::createSingleton() {
+    // This object's constructor is invoked on the first call to this method.
+    // At exit, its destructor will terminate Shibboleth.
+    static ShibFinalizer finalizer;
+}
+
+
 gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
 {
     m_initialized = false;
@@ -463,13 +515,22 @@ gss_eap_shib_attr_provider::init(void)
 {
     bool ret = false;
 
+    if (ShibFinalizer::isShibInitialized()) {
+        wpa_printf(MSG_INFO, "### gss_eap_shib_attr_provider::init(): ShibResolver library is already initialized; ignoring.");
+        return true;
+    }
+
+    wpa_printf(MSG_INFO, "### gss_eap_shib_attr_provider::init(): Initializing ShibResolver library");
+
     try {
         ret = ShibbolethResolver::init();
     } catch (exception &e) {
     }
 
-    if (ret)
+    if (ret) {
+        ShibFinalizer::createSingleton();
         gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
+    }
 
     return ret;
 }
@@ -477,6 +538,7 @@ gss_eap_shib_attr_provider::init(void)
 void
 gss_eap_shib_attr_provider::finalize(void)
 {
+    wpa_printf(MSG_INFO, "### gss_eap_shib_attr_provider::finalize(): calling ShibbolethResolver::term()");
     gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
     ShibbolethResolver::term();
 }
@@ -534,6 +596,7 @@ gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
     return dst;
 }
 
+
 OM_uint32
 gssEapLocalAttrProviderInit(OM_uint32 *minor)
 {
@@ -541,14 +604,6 @@ gssEapLocalAttrProviderInit(OM_uint32 *minor)
         *minor = GSSEAP_SHIB_INIT_FAILURE;
         return GSS_S_FAILURE;
     }
-    return GSS_S_COMPLETE;
-}
-
-OM_uint32
-gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
-{
-    gss_eap_shib_attr_provider::finalize();
 
-    *minor = 0;
     return GSS_S_COMPLETE;
 }
index bb9bf19..a93f5f8 100644 (file)
 
 #include "gssapiP_eap.h"
 
-OM_uint32 GSSAPI_CALLCONV
-gss_verify_mic_iov(OM_uint32 *minor,
-                   gss_ctx_id_t ctx,
-                   gss_qop_t *qop_state,
-                   gss_iov_buffer_desc *iov,
-                   int iov_count)
+static OM_uint32
+gssEapVerifyMIC(OM_uint32 *minor,
+                gss_ctx_id_t ctx,
+                gss_qop_t *qop_state,
+                gss_iov_buffer_desc *iov,
+                int iov_count)
 {
     OM_uint32 major;
 
@@ -79,5 +79,15 @@ gss_verify_mic(OM_uint32 *minor,
     iov[1].type = GSS_IOV_BUFFER_TYPE_MIC_TOKEN;
     iov[1].buffer = *message_token;
 
-    return gss_verify_mic_iov(minor, (gss_ctx_id_t)ctx, qop_state, iov, 2);
+    return gssEapVerifyMIC(minor, (gss_ctx_id_t)ctx, qop_state, iov, 2);
+}
+
+OM_uint32 GSSAPI_CALLCONV
+gss_verify_mic_iov(OM_uint32 *minor,
+                   gss_ctx_id_t ctx,
+                   gss_qop_t *qop_state,
+                   gss_iov_buffer_desc *iov,
+                   int iov_count)
+{
+    return gssEapVerifyMIC(minor, ctx, qop_state, iov, iov_count);
 }