support for libmoonshot identity selector
authorLuke Howard <lukeh@padl.com>
Wed, 7 Sep 2011 13:33:19 +0000 (14:33 +0100)
committerLuke Howard <lukeh@padl.com>
Fri, 9 Sep 2011 21:28:06 +0000 (22:28 +0100)
17 files changed:
libradsec
moonshot/acinclude.m4
moonshot/configure.ac
moonshot/mech_eap/Makefile.am
moonshot/mech_eap/accept_sec_context.c
moonshot/mech_eap/acquire_cred.c
moonshot/mech_eap/acquire_cred_with_password.c
moonshot/mech_eap/add_cred.c
moonshot/mech_eap/add_cred_with_password.c
moonshot/mech_eap/gssapiP_eap.h
moonshot/mech_eap/gsseap_err.et
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/set_cred_option.c
moonshot/mech_eap/util.h
moonshot/mech_eap/util_context.c
moonshot/mech_eap/util_cred.c
moonshot/mech_eap/util_moonshot.c [new file with mode: 0644]

index b6cbbcf..ade6c4f 160000 (submodule)
--- a/libradsec
+++ b/libradsec
@@ -1 +1 @@
-Subproject commit b6cbbcfa4b40bbbf29cfe62f35e9f672684d37d0
+Subproject commit ade6c4fa17f837504a3902296d4b4f636e28b51e
index 80c71bb..f8a7efb 100644 (file)
@@ -258,3 +258,43 @@ else
        AC_SUBST(JANSSON_LIBS)
 fi
 ])dnl
+
+AC_DEFUN([AX_CHECK_LIBMOONSHOT],
+[AC_MSG_CHECKING(for Moonshot identity selector implementation)
+LIBMOONSHOT_DIR=
+found_libmoonshot="no"
+AC_ARG_WITH(libmoonshot,
+    AC_HELP_STRING([--with-libmoonshot],
+       [Use libmoonshot (in specified installation directory)]),
+    [check_libmoonshot_dir="$withval"],
+    [check_libmoonshot_dir=])
+for dir in $check_libmoonshot_dir $prefix /usr /usr/local ../../moonshot-ui/libmoonshot ; do
+   libmoonshotdir="$dir"
+   if test -f "$dir/include/libmoonshot.h"; then
+     found_libmoonshot="yes";
+     LIBMOONSHOT_DIR="${libmoonshotdir}"
+     LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include";
+     break;
+   fi
+done
+AC_MSG_RESULT($found_libmoonshot)
+if test x_$found_libmoonshot != x_yes; then
+   AC_MSG_ERROR([
+----------------------------------------------------------------------
+  Cannot find Moonshot identity selector libraries.
+
+  Please install wpa_supplicant or specify installation directory with
+  --with-libmoonshot=(dir).
+----------------------------------------------------------------------
+])
+else
+       printf "libmoonshot found in $libmoonshotdir\n";
+       LIBMOONSHOT_LIBS="-lmoonshot";
+       LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib";
+       AC_SUBST(LIBMOONSHOT_CFLAGS)
+       AC_SUBST(LIBMOONSHOT_LDFLAGS)
+       AC_SUBST(LIBMOONSHOT_LIBS)
+       AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS")
+fi
+])dnl
+
index 5ab930c..ccf5832 100644 (file)
@@ -53,5 +53,6 @@ AX_CHECK_SHIBSP
 AX_CHECK_SHIBRESOLVER
 AX_CHECK_RADSEC
 AX_CHECK_JANSSON
+AX_CHECK_LIBMOONSHOT
 AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile])
 AC_OUTPUT
index 55014cb..1f26d7d 100644 (file)
@@ -85,6 +85,7 @@ mech_eap_la_SOURCES =                         \
        util_krb.c                              \
        util_lucid.c                            \
        util_mech.c                             \
+       util_moonshot.c                         \
        util_name.c                             \
        util_oid.c                              \
        util_ordering.c                         \
index cc8702d..afbd554 100644 (file)
@@ -431,10 +431,10 @@ createRadiusHandle(OM_uint32 *minor,
         return GSS_S_FAILURE;
     }
 
-    if (cred->radiusConfigFile != NULL)
-        configFile = cred->radiusConfigFile;
-    if (cred->radiusConfigStanza != NULL)
-        configStanza = cred->radiusConfigStanza;
+    if (cred->radiusConfigFile.value != NULL)
+        configFile = (const char *)cred->radiusConfigFile.value;
+    if (cred->radiusConfigStanza.value != NULL)
+        configStanza = (const char *)cred->radiusConfigStanza.value;
 
     ralloc.calloc  = GSSEAP_CALLOC;
     ralloc.malloc  = GSSEAP_MALLOC;
@@ -840,30 +840,31 @@ gss_accept_sec_context(OM_uint32 *minor,
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
     if (cred == GSS_C_NO_CREDENTIAL) {
-        if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
+        if (ctx->cred == GSS_C_NO_CREDENTIAL) {
             major = gssEapAcquireCred(minor,
                                       GSS_C_NO_NAME,
-                                      GSS_C_NO_BUFFER,
                                       GSS_C_INDEFINITE,
                                       GSS_C_NO_OID_SET,
                                       GSS_C_ACCEPT,
-                                      &ctx->defaultCred,
+                                      &ctx->cred,
                                       NULL,
                                       NULL);
             if (GSS_ERROR(major))
                 goto cleanup;
         }
 
-        cred = ctx->defaultCred;
+        cred = ctx->cred;
     }
 
     GSSEAP_MUTEX_LOCK(&cred->mutex);
 
-    if (cred->name != GSS_C_NO_NAME) {
-        major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
-        if (GSS_ERROR(major))
-            goto cleanup;
-    }
+    /*
+     * Calling gssEapInquireCred() forces the default acceptor credential name
+     * to be resolved.
+     */
+    major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
+    if (GSS_ERROR(major))
+        goto cleanup;
 
     major = gssEapSmStep(minor,
                          cred,
index 2326eaa..9e3f027 100644 (file)
@@ -46,7 +46,7 @@ gss_acquire_cred(OM_uint32 *minor,
                  gss_OID_set *actual_mechs,
                  OM_uint32 *time_rec)
 {
-    return gssEapAcquireCred(minor, desired_name, GSS_C_NO_BUFFER,
+    return gssEapAcquireCred(minor, desired_name,
                              time_req, desired_mechs, cred_usage,
                              output_cred_handle, actual_mechs, time_rec);
 }
index c0f4159..466473b 100644 (file)
@@ -47,7 +47,21 @@ gssspi_acquire_cred_with_password(OM_uint32 *minor,
                                   gss_OID_set *actual_mechs,
                                   OM_uint32 *time_rec)
 {
-    return gssEapAcquireCred(minor, desired_name, password,
-                             time_req, desired_mechs, cred_usage,
-                             output_cred_handle, actual_mechs, time_rec);
+    OM_uint32 major, tmpMinor;
+
+    major = gssEapAcquireCred(minor, desired_name,
+                              time_req, desired_mechs, cred_usage,
+                              output_cred_handle, actual_mechs, time_rec);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+cleanup:
+    if (GSS_ERROR(major))
+        gssEapReleaseCred(&tmpMinor, output_cred_handle);
+
+    return major;
 }
index 37d0add..f1598ed 100644 (file)
@@ -71,7 +71,6 @@ gss_add_cred(OM_uint32 *minor,
 
     major = gssEapAcquireCred(minor,
                               desired_name,
-                              GSS_C_NO_BUFFER,
                               time_req,
                               &mechs,
                               cred_usage,
index 7907138..f634f96 100644 (file)
@@ -50,7 +50,7 @@ gss_add_cred_with_password(OM_uint32 *minor,
                            OM_uint32 *initiator_time_rec,
                            OM_uint32 *acceptor_time_rec)
 {
-    OM_uint32 major;
+    OM_uint32 major, tmpMinor;
     OM_uint32 time_req, time_rec = 0;
     gss_OID_set_desc mechs;
 
@@ -67,18 +67,27 @@ gss_add_cred_with_password(OM_uint32 *minor,
 
     major = gssEapAcquireCred(minor,
                               desired_name,
-                              password,
                               time_req,
                               &mechs,
                               cred_usage,
                               output_cred_handle,
                               actual_mechs,
                               &time_rec);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
+    if (GSS_ERROR(major))
+        goto cleanup;
 
     if (initiator_time_rec != NULL)
         *initiator_time_rec = time_rec;
     if (acceptor_time_rec != NULL)
         *acceptor_time_rec = time_rec;
 
+cleanup:
+    if (GSS_ERROR(major))
+        gssEapReleaseCred(&tmpMinor, output_cred_handle);
+
     return major;
 }
index 8bad9a8..cb67110 100644 (file)
@@ -118,9 +118,9 @@ struct gss_name_struct
 
 #define CRED_FLAG_INITIATE                  0x00010000
 #define CRED_FLAG_ACCEPT                    0x00020000
-#define CRED_FLAG_DEFAULT_IDENTITY          0x00040000
-#define CRED_FLAG_PASSWORD                  0x00080000
-#define CRED_FLAG_DEFAULT_CCACHE            0x00100000
+#define CRED_FLAG_PASSWORD                  0x00040000
+#define CRED_FLAG_DEFAULT_CCACHE            0x00080000
+#define CRED_FLAG_RESOLVED                  0x00100000
 #define CRED_FLAG_PUBLIC_MASK               0x0000FFFF
 
 #ifdef HAVE_HEIMDAL_VERSION
@@ -132,11 +132,15 @@ struct gss_cred_id_struct
     GSSEAP_MUTEX mutex;
     OM_uint32 flags;
     gss_name_t name;
+    gss_name_t target; /* for initiator */
     gss_buffer_desc password;
     gss_OID_set mechanisms;
     time_t expiryTime;
-    char *radiusConfigFile;
-    char *radiusConfigStanza;
+    gss_buffer_desc radiusConfigFile;
+    gss_buffer_desc radiusConfigStanza;
+    gss_buffer_desc caCertificate;
+    gss_buffer_desc subjectNameConstraint;
+    gss_buffer_desc subjectAltNameConstraint;
 #ifdef GSSEAP_ENABLE_REAUTH
     krb5_ccache krbCredCache;
     gss_cred_id_t reauthCred;
@@ -196,7 +200,7 @@ struct gss_ctx_id_struct
     time_t expiryTime;
     uint64_t sendSeq, recvSeq;
     void *seqState;
-    gss_cred_id_t defaultCred;
+    gss_cred_id_t cred;
     union {
         struct gss_eap_initiator_ctx initiator;
         #define initiatorCtx         ctxU.initiator
index 6bcfff0..f8ec5ef 100644 (file)
@@ -82,6 +82,18 @@ error_code GSSEAP_CRED_EXPIRED,                 "Attributes indicate credentials
 error_code GSSEAP_BAD_CRED_OPTION,              "Bad credential option"
 error_code GSSEAP_NO_DEFAULT_IDENTITY,          "Default credentials identity unavailable"
 error_code GSSEAP_NO_DEFAULT_CRED,              "Missing default password or other credentials"
+error_code GSSEAP_CRED_RESOLVED,                "Credential is already fully resolved"
+
+#
+# Local identity service errors
+#
+error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE,     "Unable to start identity service"
+error_code GSSEAP_NO_IDENTITY_SELECTED,                 "No identity selected"
+error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR,       "Identity service installation error"
+error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR,            "Identity service OS error"
+error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR,           "Identity service IPC error"
+error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR,       "Unknown identity service error"
+
 #
 # Wrap/unwrap/PRF errors
 #
index 42f9b93..e08e059 100644 (file)
@@ -195,15 +195,14 @@ extern int wpa_debug_level;
 #endif
 
 static OM_uint32
-peerConfigInit(OM_uint32 *minor,
-               gss_cred_id_t cred,
-               gss_ctx_id_t ctx)
+peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
 {
     OM_uint32 major;
     krb5_context krbContext;
     struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
     gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
+    gss_cred_id_t cred = ctx->cred;
 
     eapPeerConfig->identity = NULL;
     eapPeerConfig->identity_len = 0;
@@ -254,6 +253,11 @@ peerConfigInit(OM_uint32 *minor,
     eapPeerConfig->password = (unsigned char *)cred->password.value;
     eapPeerConfig->password_len = cred->password.length;
 
+    /* certs */
+    eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
+    eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
+    eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
+
     *minor = 0;
     return GSS_S_COMPLETE;
 }
@@ -341,7 +345,6 @@ initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
 
 static OM_uint32
 initBegin(OM_uint32 *minor,
-          gss_cred_id_t cred,
           gss_ctx_id_t ctx,
           gss_name_t target,
           gss_OID mech,
@@ -350,6 +353,7 @@ initBegin(OM_uint32 *minor,
           gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
 {
     OM_uint32 major;
+    gss_cred_id_t cred = ctx->cred;
 
     assert(cred != GSS_C_NO_CREDENTIAL);
 
@@ -634,7 +638,7 @@ eapGssSmInitIdentity(OM_uint32 *minor,
 
 static OM_uint32
 eapGssSmInitAuthenticate(OM_uint32 *minor,
-                         gss_cred_id_t cred,
+                         gss_cred_id_t cred GSSEAP_UNUSED,
                          gss_ctx_id_t ctx,
                          gss_name_t target GSSEAP_UNUSED,
                          gss_OID mech GSSEAP_UNUSED,
@@ -653,7 +657,7 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
 
     assert(inputToken != GSS_C_NO_BUFFER);
 
-    major = peerConfigInit(minor, cred, ctx);
+    major = peerConfigInit(minor, ctx);
     if (GSS_ERROR(major))
         goto cleanup;
 
@@ -938,34 +942,24 @@ gss_init_sec_context(OM_uint32 *minor,
 
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
-    if (cred == GSS_C_NO_CREDENTIAL) {
-        if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
-            major = gssEapAcquireCred(minor,
-                                      GSS_C_NO_NAME,
-                                      GSS_C_NO_BUFFER,
-                                      time_req,
-                                      GSS_C_NO_OID_SET,
-                                      GSS_C_INITIATE,
-                                      &ctx->defaultCred,
-                                      NULL,
-                                      NULL);
-            if (GSS_ERROR(major))
-                goto cleanup;
-        }
+    if (cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_LOCK(&cred->mutex);
 
-        cred = ctx->defaultCred;
+    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
+        major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        assert(ctx->cred != GSS_C_NO_CREDENTIAL);
     }
 
-    GSSEAP_MUTEX_LOCK(&cred->mutex);
+    GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
 
-    if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
-        major = GSS_S_NO_CRED;
-        *minor = GSSEAP_CRED_USAGE_MISMATCH;
-        goto cleanup;
-    }
+    assert(ctx->cred->flags & CRED_FLAG_RESOLVED);
+    assert(ctx->cred->flags & CRED_FLAG_INITIATE);
 
     if (initialContextToken) {
-        major = initBegin(minor, cred, ctx, target_name, mech_type,
+        major = initBegin(minor, ctx, target_name, mech_type,
                           req_flags, time_req, input_chan_bindings);
         if (GSS_ERROR(major))
             goto cleanup;
@@ -1006,6 +1000,8 @@ gss_init_sec_context(OM_uint32 *minor,
 cleanup:
     if (cred != GSS_C_NO_CREDENTIAL)
         GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+    if (ctx->cred != GSS_C_NO_CREDENTIAL)
+        GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
 
     if (GSS_ERROR(major))
index bfffa1f..dd87a1f 100644 (file)
@@ -42,7 +42,7 @@ setCredRadiusConfigFile(OM_uint32 *minor,
                         const gss_OID oid GSSEAP_UNUSED,
                         const gss_buffer_t buffer)
 {
-    OM_uint32 major;
+    OM_uint32 major, tmpMinor;
     gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
 
     if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
@@ -51,10 +51,8 @@ setCredRadiusConfigFile(OM_uint32 *minor,
             return major;
     }
 
-    if (cred->radiusConfigFile != NULL)
-        GSSEAP_FREE(cred->radiusConfigFile);
-
-    cred->radiusConfigFile = (char *)configFileBuffer.value;
+    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
+    cred->radiusConfigFile = configFileBuffer;
 
     *minor = 0;
     return GSS_S_COMPLETE;
@@ -66,7 +64,7 @@ setCredRadiusConfigStanza(OM_uint32 *minor,
                           const gss_OID oid GSSEAP_UNUSED,
                           const gss_buffer_t buffer)
 {
-    OM_uint32 major;
+    OM_uint32 major, tmpMinor;
     gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER;
 
     if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
@@ -75,10 +73,8 @@ setCredRadiusConfigStanza(OM_uint32 *minor,
             return major;
     }
 
-    if (cred->radiusConfigStanza != NULL)
-        GSSEAP_FREE(cred->radiusConfigStanza);
-
-    cred->radiusConfigStanza = (char *)configStanzaBuffer.value;
+    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
+    cred->radiusConfigStanza = configStanzaBuffer;
 
     *minor = 0;
     return GSS_S_COMPLETE;
index 4de00e3..748350d 100644 (file)
@@ -76,7 +76,7 @@ extern "C" {
 #endif
 
 #if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-#define GSSEAP_UNUSED __attribute__ ((__unused__)) 
+#define GSSEAP_UNUSED __attribute__ ((__unused__))
 #else
 #define GSSEAP_UNUSED
 #endif
@@ -87,6 +87,13 @@ makeStringBuffer(OM_uint32 *minor,
                  const char *string,
                  gss_buffer_t buffer);
 
+#define makeStringBufferOrCleanup(src, dst)             \
+    do {                                                \
+        major = makeStringBuffer((minor), (src), (dst));\
+        if (GSS_ERROR(major))                           \
+            goto cleanup;                               \
+    } while (0)
+
 OM_uint32
 bufferToString(OM_uint32 *minor,
                const gss_buffer_t buffer,
@@ -97,6 +104,13 @@ duplicateBuffer(OM_uint32 *minor,
                 const gss_buffer_t src,
                 gss_buffer_t dst);
 
+#define duplicateBufferOrCleanup(src, dst)              \
+    do {                                                \
+        major = duplicateBuffer((minor), (src), (dst)); \
+        if (GSS_ERROR(major))                           \
+            goto cleanup;                               \
+    } while (0)
+
 static inline int
 bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
 {
@@ -209,10 +223,12 @@ gssEapContextTime(OM_uint32 *minor,
 OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
 OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
 
+gss_OID
+gssEapPrimaryMechForCred(gss_cred_id_t cred);
+
 OM_uint32
 gssEapAcquireCred(OM_uint32 *minor,
                   const gss_name_t desiredName,
-                  const gss_buffer_t password,
                   OM_uint32 timeReq,
                   const gss_OID_set desiredMechs,
                   int cred_usage,
@@ -220,6 +236,22 @@ gssEapAcquireCred(OM_uint32 *minor,
                   gss_OID_set *pActualMechs,
                   OM_uint32 *timeRec);
 
+OM_uint32
+gssEapSetCredPassword(OM_uint32 *minor,
+                      gss_cred_id_t cred,
+                      const gss_buffer_t password);
+
+OM_uint32
+gssEapSetCredService(OM_uint32 *minor,
+                     gss_cred_id_t cred,
+                     const gss_name_t target);
+
+OM_uint32
+gssEapResolveInitiatorCred(OM_uint32 *minor,
+                           const gss_cred_id_t cred,
+                           const gss_name_t target,
+                           gss_cred_id_t *resolvedCred);
+
 int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
 
 OM_uint32
@@ -457,6 +489,17 @@ gssEapOidToSaslName(const gss_OID oid);
 gss_OID
 gssEapSaslNameToOid(const gss_buffer_t name);
 
+/* util_moonshot.c */
+OM_uint32
+libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
+                                  const gss_cred_id_t cred,
+                                  gss_name_t *pName);
+
+OM_uint32
+libMoonshotResolveInitiatorCred(OM_uint32 *minor,
+                                gss_cred_id_t cred,
+                                const gss_name_t targetName);
+
 /* util_name.c */
 #define EXPORT_NAME_FLAG_OID                    0x1
 #define EXPORT_NAME_FLAG_COMPOSITE              0x2
index 5a39424..054fa0f 100644 (file)
@@ -130,7 +130,7 @@ gssEapReleaseContext(OM_uint32 *minor,
     gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
     gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
     sequenceFree(&tmpMinor, &ctx->seqState);
-    gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
+    gssEapReleaseCred(&tmpMinor, &ctx->cred);
 
     GSSEAP_MUTEX_DESTROY(&ctx->mutex);
 
index 28cb76c..4c8c8c7 100644 (file)
@@ -64,6 +64,18 @@ gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
     return GSS_S_COMPLETE;
 }
 
+static void
+zeroAndReleasePassword(gss_buffer_t password)
+{
+    if (password->value != NULL) {
+        memset(password->value, 0, password->length);
+        GSSEAP_FREE(password->value);
+    }
+
+    password->value = NULL;
+    password->length = 0;
+}
+
 OM_uint32
 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
 {
@@ -78,16 +90,15 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
     GSSEAP_KRB_INIT(&krbContext);
 
     gssEapReleaseName(&tmpMinor, &cred->name);
+    gssEapReleaseName(&tmpMinor, &cred->target);
 
-    if (cred->password.value != NULL) {
-        memset(cred->password.value, 0, cred->password.length);
-        GSSEAP_FREE(cred->password.value);
-    }
+    zeroAndReleasePassword(&cred->password);
 
-    if (cred->radiusConfigFile != NULL)
-        GSSEAP_FREE(cred->radiusConfigFile);
-    if (cred->radiusConfigStanza != NULL)
-        GSSEAP_FREE(cred->radiusConfigStanza);
+    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
+    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
+    gss_release_buffer(&tmpMinor, &cred->caCertificate);
+    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
+    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
 
 #ifdef GSSEAP_ENABLE_REAUTH
     if (cred->krbCredCache != NULL) {
@@ -110,21 +121,24 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
 }
 
 static OM_uint32
-readDefaultIdentityAndCreds(OM_uint32 *minor,
-                            gss_buffer_t defaultIdentity,
-                            gss_buffer_t defaultCreds)
+readStaticIdentityFile(OM_uint32 *minor,
+                       gss_buffer_t defaultIdentity,
+                       gss_buffer_t defaultPassword)
 {
     OM_uint32 major, tmpMinor;
     FILE *fp = NULL;
     char pwbuf[BUFSIZ], buf[BUFSIZ];
     char *ccacheName;
     struct passwd *pw = NULL, pwd;
+    int i = 0;
 
     defaultIdentity->length = 0;
     defaultIdentity->value = NULL;
 
-    defaultCreds->length = 0;
-    defaultCreds->value = NULL;
+    if (defaultPassword != GSS_C_NO_BUFFER) {
+        defaultPassword->length = 0;
+        defaultPassword->value = NULL;
+    }
 
     ccacheName = getenv("GSSEAP_IDENTITY");
     if (ccacheName == NULL) {
@@ -161,16 +175,20 @@ readDefaultIdentityAndCreds(OM_uint32 *minor,
                 break;
         }
 
-        if (defaultIdentity->value == NULL)
+        if (i == 0)
             dst = defaultIdentity;
-        else if (defaultCreds->value == NULL)
-            dst = defaultCreds;
+        else if (i == 1)
+            dst = defaultPassword;
         else
             break;
 
-        major = duplicateBuffer(minor, &src, dst);
-        if (GSS_ERROR(major))
-            goto cleanup;
+        if (dst != GSS_C_NO_BUFFER) {
+            major = duplicateBuffer(minor, &src, dst);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        }
+
+        i++;
     }
 
     if (defaultIdentity->length == 0) {
@@ -188,16 +206,29 @@ cleanup:
 
     if (GSS_ERROR(major)) {
         gss_release_buffer(&tmpMinor, defaultIdentity);
-        gss_release_buffer(&tmpMinor, defaultCreds);
+        zeroAndReleasePassword(defaultPassword);
     }
 
+    memset(buf, 0, sizeof(buf));
+
     return major;
 }
 
+gss_OID
+gssEapPrimaryMechForCred(gss_cred_id_t cred)
+{
+    gss_OID nameMech = GSS_C_NO_OID;
+
+    if (cred->mechanisms != GSS_C_NO_OID_SET &&
+        cred->mechanisms->count == 1)
+        nameMech = &cred->mechanisms->elements[0];
+
+    return nameMech;
+}
+
 OM_uint32
 gssEapAcquireCred(OM_uint32 *minor,
                   const gss_name_t desiredName,
-                  const gss_buffer_t password,
                   OM_uint32 timeReq GSSEAP_UNUSED,
                   const gss_OID_set desiredMechs,
                   int credUsage,
@@ -207,10 +238,6 @@ gssEapAcquireCred(OM_uint32 *minor,
 {
     OM_uint32 major, tmpMinor;
     gss_cred_id_t cred;
-    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
-    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
-    gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
-    gss_OID nameMech = GSS_C_NO_OID;
 
     /* XXX TODO validate with changed set_cred_option API */
     *pCred = GSS_C_NO_CREDENTIAL;
@@ -244,21 +271,6 @@ gssEapAcquireCred(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
-    if (cred->mechanisms != GSS_C_NO_OID_SET &&
-        cred->mechanisms->count == 1)
-        nameMech = &cred->mechanisms->elements[0];
-
-    if (cred->flags & CRED_FLAG_INITIATE) {
-        major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
-        if (major == GSS_S_COMPLETE) {
-            major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
-                                     nameMech, &defaultIdentityName);
-            if (GSS_ERROR(major))
-                goto cleanup;
-        } else if (major != GSS_S_CRED_UNAVAIL)
-            goto cleanup;
-    }
-
     if (desiredName != GSS_C_NO_NAME) {
         GSSEAP_MUTEX_LOCK(&desiredName->mutex);
 
@@ -269,78 +281,6 @@ gssEapAcquireCred(OM_uint32 *minor,
         }
 
         GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
-
-        if (defaultIdentityName != GSS_C_NO_NAME) {
-            int nameEqual;
-
-            major = gssEapCompareName(minor, desiredName,
-                                      defaultIdentityName, &nameEqual);
-            if (GSS_ERROR(major))
-                goto cleanup;
-            else if (nameEqual)
-                cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
-        }
-    } else {
-        if (cred->flags & CRED_FLAG_ACCEPT) {
-            gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-            char serviceName[5 + MAXHOSTNAMELEN];
-
-            /* default host-based service is host@localhost */
-            memcpy(serviceName, "host@", 5);
-            if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
-                major = GSS_S_FAILURE;
-                *minor = GSSEAP_NO_HOSTNAME;
-                goto cleanup;
-            }
-
-            nameBuf.value = serviceName;
-            nameBuf.length = strlen((char *)nameBuf.value);
-
-            major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
-                                     nameMech, &cred->name);
-            if (GSS_ERROR(major))
-                goto cleanup;
-        } else if (cred->flags & CRED_FLAG_INITIATE) {
-            if (defaultIdentityName == GSS_C_NO_NAME) {
-                major = GSS_S_CRED_UNAVAIL;
-                *minor = GSSEAP_NO_DEFAULT_IDENTITY;
-                goto cleanup;
-            }
-
-            cred->name = defaultIdentityName;
-            defaultIdentityName = GSS_C_NO_NAME;
-        }
-        cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
-    }
-
-    assert(cred->name != GSS_C_NO_NAME);
-
-    if (password != GSS_C_NO_BUFFER) {
-        major = duplicateBuffer(minor, password, &cred->password);
-        if (GSS_ERROR(major))
-            goto cleanup;
-
-        cred->flags |= CRED_FLAG_PASSWORD;
-    } else if (defaultCreds.value != NULL &&
-        (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
-        cred->password = defaultCreds;
-
-        defaultCreds.length = 0;
-        defaultCreds.value = NULL;
-
-        cred->flags |= CRED_FLAG_PASSWORD;
-    } else if (cred->flags & CRED_FLAG_INITIATE) {
-        /*
-         * OK, here we need to ask the supplicant if we have creds or it
-         * will acquire them, so GS2 can know whether to prompt for a
-         * password or not.
-         */
-#if 0
-        && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
-#endif
-        major = GSS_S_CRED_UNAVAIL;
-        *minor = GSSEAP_NO_DEFAULT_CRED;
-        goto cleanup;
     }
 
     if (pActualMechs != NULL) {
@@ -360,12 +300,6 @@ gssEapAcquireCred(OM_uint32 *minor,
 cleanup:
     if (GSS_ERROR(major))
         gssEapReleaseCred(&tmpMinor, &cred);
-    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
-    gss_release_buffer(&tmpMinor, &defaultIdentity);
-    if (defaultCreds.value != NULL) {
-        memset(defaultCreds.value, 0, defaultCreds.length);
-        gss_release_buffer(&tmpMinor, &defaultCreds);
-    }
 
     return major;
 }
@@ -390,6 +324,72 @@ gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
     return present;
 }
 
+static OM_uint32
+staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
+                                         const gss_cred_id_t cred,
+                                         gss_name_t *pName)
+{
+    OM_uint32 major, tmpMinor;
+    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
+    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
+
+    *pName = GSS_C_NO_NAME;
+
+    major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
+    if (major == GSS_S_COMPLETE) {
+        major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
+                                 nameMech, pName);
+    }
+
+    gss_release_buffer(&tmpMinor, &defaultIdentity);
+
+    return major;
+}
+
+static OM_uint32
+gssEapResolveCredIdentity(OM_uint32 *minor,
+                          gss_cred_id_t cred)
+{
+    OM_uint32 major;
+    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
+
+    if (cred->name != GSS_C_NO_NAME) {
+        *minor = 0;
+        return GSS_S_COMPLETE;
+    }
+
+    if (cred->flags & CRED_FLAG_ACCEPT) {
+        gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+        char serviceName[5 + MAXHOSTNAMELEN];
+
+        /* default host-based service is host@localhost */
+        memcpy(serviceName, "host@", 5);
+        if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
+            *minor = GSSEAP_NO_HOSTNAME;
+            return GSS_S_FAILURE;
+        }
+
+        nameBuf.value = serviceName;
+        nameBuf.length = strlen((char *)nameBuf.value);
+
+        major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
+                                 nameMech, &cred->name);
+        if (GSS_ERROR(major))
+            return major;
+    } else if (cred->flags & CRED_FLAG_INITIATE) {
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
+        major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
+        if (major == GSS_S_CRED_UNAVAIL)
+#endif
+            major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
+        if (major != GSS_S_CRED_UNAVAIL)
+            return major;
+    }
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
 OM_uint32
 gssEapInquireCred(OM_uint32 *minor,
                   gss_cred_id_t cred,
@@ -402,9 +402,16 @@ gssEapInquireCred(OM_uint32 *minor,
     time_t now, lifetime;
 
     if (name != NULL) {
-        major = gssEapDuplicateName(minor, cred->name, name);
+        major = gssEapResolveCredIdentity(minor, cred);
         if (GSS_ERROR(major))
-            return major;
+            goto cleanup;
+
+        if (cred->name != GSS_C_NO_NAME) {
+            major = gssEapDuplicateName(minor, cred->name, name);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        } else
+            *name = GSS_C_NO_NAME;
     }
 
     if (cred_usage != NULL) {
@@ -429,7 +436,7 @@ gssEapInquireCred(OM_uint32 *minor,
         else
             major = gssEapIndicateMechs(minor, mechanisms);
         if (GSS_ERROR(major))
-            return major;
+            goto cleanup;
     }
 
     if (cred->expiryTime == 0) {
@@ -446,12 +453,233 @@ gssEapInquireCred(OM_uint32 *minor,
     }
 
     if (lifetime == 0) {
+        major = GSS_S_CREDENTIALS_EXPIRED;
         *minor = GSSEAP_CRED_EXPIRED;
-        return GSS_S_CREDENTIALS_EXPIRED;
+        goto cleanup;
     }
 
     major = GSS_S_COMPLETE;
     *minor = 0;
 
+cleanup:
+    return major;
+}
+
+OM_uint32
+gssEapSetCredPassword(OM_uint32 *minor,
+                      gss_cred_id_t cred,
+                      const gss_buffer_t password)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
+
+    if (cred->flags & CRED_FLAG_RESOLVED) {
+        major = GSS_S_FAILURE;
+        *minor = GSSEAP_CRED_RESOLVED;
+        goto cleanup;
+    }
+
+    if (password != GSS_C_NO_BUFFER) {
+        major = duplicateBuffer(minor, password, &newPassword);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        cred->flags |= CRED_FLAG_PASSWORD;
+    } else {
+        cred->flags &= ~(CRED_FLAG_PASSWORD);
+    }
+
+    gss_release_buffer(&tmpMinor, &cred->password);
+    cred->password = newPassword;
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    return major;
+}
+
+static OM_uint32
+gssEapDuplicateCred(OM_uint32 *minor,
+                    const gss_cred_id_t src,
+                    gss_cred_id_t *pDst)
+{
+    OM_uint32 major, tmpMinor;
+    gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
+
+    *pDst = GSS_C_NO_CREDENTIAL;
+
+    major = gssEapAllocCred(minor, &dst);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    dst->flags = src->flags;
+
+    if (src->name != GSS_C_NO_NAME) {
+        major = gssEapDuplicateName(minor, src->name, &dst->name);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if (src->target != GSS_C_NO_NAME) {
+        major = gssEapDuplicateName(minor, src->target, &dst->target);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if (src->password.value != NULL) {
+        major = duplicateBuffer(minor, &src->password, &dst->password);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    dst->expiryTime = src->expiryTime;
+
+    if (src->radiusConfigFile.value != NULL)
+        duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
+    if (src->radiusConfigStanza.value != NULL)
+        duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
+    if (src->caCertificate.value != NULL)
+        duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
+    if (src->subjectNameConstraint.value != NULL)
+        duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
+    if (src->subjectAltNameConstraint.value != NULL)
+        duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+    /* XXX krbCredCache, reauthCred */
+#endif
+
+    *pDst = dst;
+    dst = GSS_C_NO_CREDENTIAL;
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    gssEapReleaseCred(&tmpMinor, &dst);
+
+    return major;
+}
+
+static OM_uint32
+staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
+    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
+    gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
+    int isDefaultIdentity = FALSE;
+
+    major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
+                             gssEapPrimaryMechForCred(cred), &defaultIdentityName);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    if (defaultIdentityName == GSS_C_NO_NAME) {
+        if (cred->name == GSS_C_NO_NAME) {
+            major = GSS_S_CRED_UNAVAIL;
+            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
+            goto cleanup;
+        }
+    } else {
+        if (cred->name == GSS_C_NO_NAME) {
+            cred->name = defaultIdentityName;
+            defaultIdentityName = GSS_C_NO_NAME;
+            isDefaultIdentity = TRUE;
+        } else {
+            major = gssEapCompareName(minor, cred->name,
+                                      defaultIdentityName, &isDefaultIdentity);
+            if (GSS_ERROR(major))
+                goto cleanup;
+        }
+    }
+
+    if (isDefaultIdentity &&
+        (cred->flags & CRED_FLAG_PASSWORD) == 0) {
+        major = gssEapSetCredPassword(minor, cred, &defaultPassword);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+cleanup:
+    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
+    zeroAndReleasePassword(&defaultPassword);
+    gss_release_buffer(&tmpMinor, &defaultIdentity);
+
+    return major;
+}
+
+OM_uint32
+gssEapResolveInitiatorCred(OM_uint32 *minor,
+                           const gss_cred_id_t cred,
+                           const gss_name_t targetName
+#ifndef HAVE_MOONSHOT_GET_IDENTITY
+                                                       GSSEAP_UNUSED
+#endif
+                           ,
+                           gss_cred_id_t *pResolvedCred)
+{
+    OM_uint32 major, tmpMinor;
+    gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
+
+    if (cred == GSS_C_NO_CREDENTIAL) {
+        major = gssEapAcquireCred(minor,
+                                  GSS_C_NO_NAME,
+                                  GSS_C_INDEFINITE,
+                                  GSS_C_NO_OID_SET,
+                                  GSS_C_INITIATE,
+                                  &resolvedCred,
+                                  NULL,
+                                  NULL);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    } else {
+        if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
+            major = GSS_S_NO_CRED;
+            *minor = GSSEAP_CRED_USAGE_MISMATCH;
+            goto cleanup;
+        }
+
+        major = gssEapDuplicateCred(minor, cred, &resolvedCred);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
+        major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
+        if (major == GSS_S_CRED_UNAVAIL)
+#endif
+            major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
+            major = GSS_S_CRED_UNAVAIL;
+            *minor = GSSEAP_NO_DEFAULT_CRED;
+            goto cleanup;
+        }
+
+        resolvedCred->flags |= CRED_FLAG_RESOLVED;
+    }
+
+    *pResolvedCred = resolvedCred;
+    resolvedCred = GSS_C_NO_CREDENTIAL;
+
+    major = GSS_S_COMPLETE;
+    *minor = 0;
+
+cleanup:
+    gssEapReleaseCred(&tmpMinor, &resolvedCred);
+
     return major;
 }
diff --git a/moonshot/mech_eap/util_moonshot.c b/moonshot/mech_eap/util_moonshot.c
new file mode 100644 (file)
index 0000000..75db452
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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"
+
+#ifdef HAVE_MOONSHOT_GET_IDENTITY
+#include <libmoonshot.h>
+
+static OM_uint32
+libMoonshotMapError(OM_uint32 *minor,
+                    MoonshotError **pError)
+{
+    MoonshotError *error = *pError;
+
+    assert(error != NULL);
+
+    switch (error->code) {
+    case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
+        *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
+        break;
+    case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
+        *minor = GSSEAP_NO_IDENTITY_SELECTED;
+        break;
+    case MOONSHOT_ERROR_INSTALLATION_ERROR:
+        *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
+        break;
+    case MOONSHOT_ERROR_OS_ERROR:
+        *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
+        break;
+    case MOONSHOT_ERROR_IPC_ERROR:
+        *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
+        break;
+    default:
+        *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
+        break;
+    }
+
+    gssEapSaveStatusInfo(*minor, error->message);
+    moonshot_error_free(error);
+    *pError = NULL;
+
+    return GSS_S_CRED_UNAVAIL;
+}
+
+OM_uint32
+libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
+                                  const gss_cred_id_t cred,
+                                  gss_name_t *pName)
+{
+    OM_uint32 major, tmpMinor;
+    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
+    gss_name_t name = GSS_C_NO_NAME;
+    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
+    char *nai = NULL;
+    char *password = NULL;
+    char *serverCertificateHash = NULL;
+    char *caCertificate = NULL;
+    char *subjectNameConstraint = NULL;
+    char *subjectAltNameConstraint = NULL;
+    MoonshotError *error = NULL;
+
+    *pName = GSS_C_NO_NAME;
+
+    if (!moonshot_get_default_identity(&nai,
+                                       &password,
+                                       &serverCertificateHash,
+                                       &caCertificate,
+                                       &subjectNameConstraint,
+                                       &subjectAltNameConstraint,
+                                       &error)) {
+        if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
+            major = GSS_S_CRED_UNAVAIL;
+            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
+            moonshot_error_free(error);
+        } else
+            major = libMoonshotMapError(minor, &error);
+        goto cleanup;
+    }
+
+    tmpBuffer.value = nai;
+    tmpBuffer.length = strlen(nai);
+
+    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    *pName = name;
+    name = GSS_C_NO_NAME;
+
+cleanup:
+    moonshot_free(nai);
+    moonshot_free(password);
+    moonshot_free(serverCertificateHash);
+    moonshot_free(caCertificate);
+    moonshot_free(subjectNameConstraint);
+    moonshot_free(subjectAltNameConstraint);
+
+    gssEapReleaseName(&tmpMinor, &name);
+
+    return major;
+}
+
+OM_uint32
+libMoonshotResolveInitiatorCred(OM_uint32 *minor,
+                                gss_cred_id_t cred,
+                                const gss_name_t targetName)
+{
+    OM_uint32 major, tmpMinor;
+    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
+    gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
+    char *nai = NULL;
+    char *password = NULL;
+    char *serverCertificateHash = NULL;
+    char *caCertificate = NULL;
+    char *subjectNameConstraint = NULL;
+    char *subjectAltNameConstraint = NULL;
+    MoonshotError *error = NULL;
+
+    if (cred->name != GSS_C_NO_NAME) {
+        major = gssEapExportName(minor, cred->name, &initiator);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if (targetName != GSS_C_NO_NAME) {
+        major = gssEapExportName(minor, targetName, &target);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if (!moonshot_get_identity((const char *)initiator.value,
+                               (const char *)cred->password.value,
+                               (const char *)target.value,
+                               &nai,
+                               &password,
+                               &serverCertificateHash,
+                               &caCertificate,
+                               &subjectNameConstraint,
+                               &subjectAltNameConstraint,
+                               &error)) {
+        major = libMoonshotMapError(minor, &error);
+        goto cleanup;
+    }
+
+    gssEapReleaseName(&tmpMinor, &cred->name);
+
+    tmpBuffer.value = nai;
+    tmpBuffer.length = strlen(nai);
+
+    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
+                             nameMech, &cred->name);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    tmpBuffer.value = password;
+    tmpBuffer.length = strlen(password);
+
+    major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    gss_release_buffer(&tmpMinor, &cred->caCertificate);
+    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
+    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
+
+    if (serverCertificateHash != NULL) {
+        size_t len = strlen(serverCertificateHash);
+
+        #define HASH_PREFIX             "hash://server/sha256/"
+        #define HASH_PREFIX_LEN         (sizeof(HASH_PREFIX) - 1)
+
+        cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
+        if (cred->caCertificate.value == NULL) {
+            major = GSS_S_FAILURE;
+            *minor = ENOMEM;
+            goto cleanup;
+        }
+
+        memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
+        memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
+
+        ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
+
+        cred->caCertificate.length = HASH_PREFIX_LEN + len;
+    } else if (caCertificate != NULL) {
+        makeStringBufferOrCleanup(caCertificate, &cred->caCertificate);
+    }
+
+    if (subjectNameConstraint != NULL)
+        makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
+    if (subjectAltNameConstraint != NULL)
+        makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
+
+cleanup:
+    moonshot_free(nai);
+    moonshot_free(password);
+    moonshot_free(serverCertificateHash);
+    moonshot_free(caCertificate);
+    moonshot_free(subjectNameConstraint);
+    moonshot_free(subjectAltNameConstraint);
+
+    gss_release_buffer(&tmpMinor, &initiator);
+    gss_release_buffer(&tmpMinor, &target);
+
+    return major;
+}
+#endif /* HAVE_MOONSHOT_GET_IDENTITY */