Merge branch 'master' into ext-mic
authorLuke Howard <lukeh@padl.com>
Fri, 9 Sep 2011 22:44:04 +0000 (23:44 +0100)
committerLuke Howard <lukeh@padl.com>
Fri, 9 Sep 2011 22:44:04 +0000 (23:44 +0100)
1  2 
moonshot/mech_eap/accept_sec_context.c
moonshot/mech_eap/gssapiP_eap.h
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/util.h
moonshot/mech_eap/util_context.c

@@@ -431,10 -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;
@@@ -616,40 -616,6 +616,40 @@@ cleanup
  }
  
  static OM_uint32
 +eapGssSmAcceptGssFlags(OM_uint32 *minor,
 +                       gss_cred_id_t cred GSSEAP_UNUSED,
 +                       gss_ctx_id_t ctx,
 +                       gss_name_t target GSSEAP_UNUSED,
 +                       gss_OID mech GSSEAP_UNUSED,
 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
 +                       OM_uint32 timeReq GSSEAP_UNUSED,
 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                       gss_buffer_t inputToken,
 +                       gss_buffer_t outputToken GSSEAP_UNUSED,
 +                       OM_uint32 *smFlags GSSEAP_UNUSED)
 +{
 +    unsigned char *p;
 +    OM_uint32 initiatorGssFlags;
 +
 +    assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
 +
 +    if (inputToken->length < 4) {
 +        *minor = GSSEAP_TOK_TRUNC;
 +        return GSS_S_DEFECTIVE_TOKEN;
 +    }
 +
 +    /* allow flags to grow for future expansion */
 +    p = (unsigned char *)inputToken->value + inputToken->length - 4;
 +
 +    initiatorGssFlags = load_uint32_be(p);
 +    initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK;
 +
 +    ctx->gssFlags |= initiatorGssFlags;
 +
 +    return GSS_S_CONTINUE_NEEDED;
 +}
 +
 +static OM_uint32
  eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
                                   gss_cred_id_t cred GSSEAP_UNUSED,
                                   gss_ctx_id_t ctx,
                                   gss_buffer_t outputToken GSSEAP_UNUSED,
                                   OM_uint32 *smFlags GSSEAP_UNUSED)
  {
 -    OM_uint32 major, tmpMinor;
 +    OM_uint32 major;
      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;
 +    iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
 +
 +    /* XXX necessary because decrypted in place and we verify it later */
 +    major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
 +    if (GSS_ERROR(major))
 +        return major;
  
      major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
                                      iov, 2, TOK_TYPE_WRAP);
 -    if (GSS_ERROR(major))
 +    if (GSS_ERROR(major)) {
 +        gssEapReleaseIov(iov, 2);
          return major;
 +    }
  
      if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
          !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
          *minor = 0;
      }
  
 -    gss_release_buffer(&tmpMinor, &iov[0].buffer);
 +    gssEapReleaseIov(iov, 2);
  
      return major;
  }
  
 +static OM_uint32
 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
 +                           gss_cred_id_t cred GSSEAP_UNUSED,
 +                           gss_ctx_id_t ctx,
 +                           gss_name_t target GSSEAP_UNUSED,
 +                           gss_OID mech GSSEAP_UNUSED,
 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
 +                           OM_uint32 timeReq GSSEAP_UNUSED,
 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                           gss_buffer_t inputToken,
 +                           gss_buffer_t outputToken GSSEAP_UNUSED,
 +                           OM_uint32 *smFlags GSSEAP_UNUSED)
 +{
 +    OM_uint32 major;
 +
 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
 +
 +    *minor = 0;
 +    return GSS_S_CONTINUE_NEEDED;
 +}
 +
  #ifdef GSSEAP_ENABLE_REAUTH
  static OM_uint32
  eapGssSmAcceptReauthCreds(OM_uint32 *minor,
  #endif
  
  static OM_uint32
 -eapGssSmAcceptCompleteInitiatorExts(OM_uint32 *minor,
 -                                    gss_cred_id_t cred GSSEAP_UNUSED,
 -                                    gss_ctx_id_t ctx,
 -                                    gss_name_t target GSSEAP_UNUSED,
 -                                    gss_OID mech GSSEAP_UNUSED,
 -                                    OM_uint32 reqFlags GSSEAP_UNUSED,
 -                                    OM_uint32 timeReq GSSEAP_UNUSED,
 -                                    gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 -                                    gss_buffer_t inputToken GSSEAP_UNUSED,
 -                                    gss_buffer_t outputToken GSSEAP_UNUSED,
 -                                    OM_uint32 *smFlags GSSEAP_UNUSED)
 +eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
 +                          gss_cred_id_t cred GSSEAP_UNUSED,
 +                          gss_ctx_id_t ctx,
 +                          gss_name_t target GSSEAP_UNUSED,
 +                          gss_OID mech GSSEAP_UNUSED,
 +                          OM_uint32 reqFlags GSSEAP_UNUSED,
 +                          OM_uint32 timeReq GSSEAP_UNUSED,
 +                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                          gss_buffer_t inputToken GSSEAP_UNUSED,
 +                          gss_buffer_t outputToken,
 +                          OM_uint32 *smFlags)
  {
 -    GSSEAP_SM_TRANSITION_NEXT(ctx);
 -
 -    *minor = 0;
 +    OM_uint32 major;
  
 -    return GSS_S_CONTINUE_NEEDED;
 -}
 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
 +    if (GSS_ERROR(major))
 +        return major;
  
 -static OM_uint32
 -eapGssSmAcceptCompleteAcceptorExts(OM_uint32 *minor,
 -                                   gss_cred_id_t cred GSSEAP_UNUSED,
 -                                   gss_ctx_id_t ctx,
 -                                   gss_name_t target GSSEAP_UNUSED,
 -                                   gss_OID mech GSSEAP_UNUSED,
 -                                   OM_uint32 reqFlags GSSEAP_UNUSED,
 -                                   OM_uint32 timeReq GSSEAP_UNUSED,
 -                                   gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 -                                   gss_buffer_t inputToken GSSEAP_UNUSED,
 -                                   gss_buffer_t outputToken GSSEAP_UNUSED,
 -                                   OM_uint32 *smFlags)
 -{
      GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
  
      *minor = 0;
 -    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
  
      return GSS_S_COMPLETE;
  }
@@@ -820,13 -769,6 +820,13 @@@ static struct gss_eap_sm eapGssAcceptor
          eapGssSmAcceptAuthenticate
      },
      {
 +        ITOK_TYPE_GSS_FLAGS,
 +        ITOK_TYPE_NONE,
 +        GSSEAP_STATE_INITIATOR_EXTS,
 +        0,
 +        eapGssSmAcceptGssFlags
 +    },
 +    {
          ITOK_TYPE_GSS_CHANNEL_BINDINGS,
          ITOK_TYPE_NONE,
          GSSEAP_STATE_INITIATOR_EXTS,
          eapGssSmAcceptGssChannelBindings,
      },
      {
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_INITIATOR_MIC,
          ITOK_TYPE_NONE,
          GSSEAP_STATE_INITIATOR_EXTS,
 -        0,
 -        eapGssSmAcceptCompleteInitiatorExts,
 +        SM_ITOK_FLAG_REQUIRED,
 +        eapGssSmAcceptInitiatorMIC,
      },
  #ifdef GSSEAP_ENABLE_REAUTH
      {
  #endif
      {
          ITOK_TYPE_NONE,
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_ACCEPTOR_MIC,
          GSSEAP_STATE_ACCEPTOR_EXTS,
          0,
 -        eapGssSmAcceptCompleteAcceptorExts
 +        eapGssSmAcceptAcceptorMIC
      },
  };
  
@@@ -898,30 -840,31 +898,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,
@@@ -118,9 -118,9 +118,9 @@@ struct gss_name_struc
  
  #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 +132,15 @@@ struct gss_cred_id_struc
      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 +200,7 @@@ struct gss_ctx_id_struc
      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
          #define reauthCtx            ctxU.reauth
  #endif
      } ctxU;
 +    const struct gss_eap_token_buffer_set *inputTokens;
 +    const struct gss_eap_token_buffer_set *outputTokens;
  };
  
  #define TOK_FLAG_SENDER_IS_ACCEPTOR         0x01
@@@ -195,15 -195,14 +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;
      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 +345,6 @@@ initReady(OM_uint32 *minor, gss_ctx_id_
  
  static OM_uint32
  initBegin(OM_uint32 *minor,
-           gss_cred_id_t cred,
            gss_ctx_id_t ctx,
            gss_name_t target,
            gss_OID mech,
            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 +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,
  {
      OM_uint32 major;
      OM_uint32 tmpMinor;
-     int code;
      struct wpabuf *resp = NULL;
  
      *minor = 0;
  
      assert(inputToken != GSS_C_NO_BUFFER);
  
-     major = peerConfigInit(minor, cred, ctx);
+     major = peerConfigInit(minor, ctx);
      if (GSS_ERROR(major))
          goto cleanup;
  
  
      major = GSS_S_CONTINUE_NEEDED;
  
-     code = eap_peer_sm_step(ctx->initiatorCtx.eap);
+     eap_peer_sm_step(ctx->initiatorCtx.eap);
      if (ctx->flags & CTX_FLAG_EAP_RESP) {
          ctx->flags &= ~(CTX_FLAG_EAP_RESP);
  
@@@ -715,30 -718,6 +718,30 @@@ cleanup
  }
  
  static OM_uint32
 +eapGssSmInitGssFlags(OM_uint32 *minor,
 +                     gss_cred_id_t cred GSSEAP_UNUSED,
 +                     gss_ctx_id_t ctx,
 +                     gss_name_t target GSSEAP_UNUSED,
 +                     gss_OID mech GSSEAP_UNUSED,
 +                     OM_uint32 reqFlags GSSEAP_UNUSED,
 +                     OM_uint32 timeReq GSSEAP_UNUSED,
 +                     gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                     gss_buffer_t inputToken GSSEAP_UNUSED,
 +                     gss_buffer_t outputToken,
 +                     OM_uint32 *smFlags GSSEAP_UNUSED)
 +{
 +    unsigned char wireFlags[4];
 +    gss_buffer_desc flagsBuf;
 +
 +    store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
 +
 +    flagsBuf.length = sizeof(wireFlags);
 +    flagsBuf.value = wireFlags;
 +
 +    return duplicateBuffer(minor, &flagsBuf, outputToken);
 +}
 +
 +static OM_uint32
  eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                 gss_cred_id_t cred GSSEAP_UNUSED,
                                 gss_ctx_id_t ctx,
      return GSS_S_CONTINUE_NEEDED;
  }
  
 +static OM_uint32
 +eapGssSmInitInitiatorMIC(OM_uint32 *minor,
 +                         gss_cred_id_t cred GSSEAP_UNUSED,
 +                         gss_ctx_id_t ctx,
 +                         gss_name_t target GSSEAP_UNUSED,
 +                         gss_OID mech GSSEAP_UNUSED,
 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
 +                         OM_uint32 timeReq GSSEAP_UNUSED,
 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
 +                         gss_buffer_t outputToken,
 +                         OM_uint32 *smFlags)
 +{
 +    OM_uint32 major;
 +
 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
 +
 +    *minor = 0;
 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 +
 +    return GSS_S_CONTINUE_NEEDED;
 +}
 + 
  #ifdef GSSEAP_ENABLE_REAUTH
  static OM_uint32
  eapGssSmInitReauthCreds(OM_uint32 *minor,
  #endif /* GSSEAP_ENABLE_REAUTH */
  
  static OM_uint32
 -eapGssSmInitCompleteInitiatorExts(OM_uint32 *minor,
 -                                  gss_cred_id_t cred GSSEAP_UNUSED,
 -                                  gss_ctx_id_t ctx,
 -                                  gss_name_t target GSSEAP_UNUSED,
 -                                  gss_OID mech GSSEAP_UNUSED,
 -                                  OM_uint32 reqFlags GSSEAP_UNUSED,
 -                                  OM_uint32 timeReq GSSEAP_UNUSED,
 -                                  gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 -                                  gss_buffer_t inputToken GSSEAP_UNUSED,
 -                                  gss_buffer_t outputToken GSSEAP_UNUSED,
 -                                  OM_uint32 *smFlags)
 +eapGssSmInitAcceptorMIC(OM_uint32 *minor,
 +                        gss_cred_id_t cred GSSEAP_UNUSED,
 +                        gss_ctx_id_t ctx,
 +                        gss_name_t target GSSEAP_UNUSED,
 +                        gss_OID mech GSSEAP_UNUSED,
 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
 +                        OM_uint32 timeReq GSSEAP_UNUSED,
 +                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 +                        gss_buffer_t inputToken,
 +                        gss_buffer_t outputToken GSSEAP_UNUSED,
 +                        OM_uint32 *smFlags GSSEAP_UNUSED)
  {
 -    GSSEAP_SM_TRANSITION_NEXT(ctx);
 -
 -    *minor = 0;
 -    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 +    OM_uint32 major;
  
 -    return GSS_S_CONTINUE_NEEDED;
 -}
 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
 +    if (GSS_ERROR(major))
 +        return major;
  
 -static OM_uint32
 -eapGssSmInitCompleteAcceptorExts(OM_uint32 *minor,
 -                                 gss_cred_id_t cred GSSEAP_UNUSED,
 -                                 gss_ctx_id_t ctx,
 -                                 gss_name_t target GSSEAP_UNUSED,
 -                                 gss_OID mech GSSEAP_UNUSED,
 -                                 OM_uint32 reqFlags GSSEAP_UNUSED,
 -                                 OM_uint32 timeReq GSSEAP_UNUSED,
 -                                 gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
 -                                 gss_buffer_t inputToken GSSEAP_UNUSED,
 -                                 gss_buffer_t outputToken GSSEAP_UNUSED,
 -                                 OM_uint32 *smFlags GSSEAP_UNUSED)
 -{
      GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
  
      *minor = 0;
@@@ -902,13 -869,6 +905,13 @@@ static struct gss_eap_sm eapGssInitiato
      },
      {
          ITOK_TYPE_NONE,
 +        ITOK_TYPE_GSS_FLAGS,
 +        GSSEAP_STATE_INITIATOR_EXTS,
 +        0,
 +        eapGssSmInitGssFlags
 +    },
 +    {
 +        ITOK_TYPE_NONE,
          ITOK_TYPE_GSS_CHANNEL_BINDINGS,
          GSSEAP_STATE_INITIATOR_EXTS,
          SM_ITOK_FLAG_REQUIRED,
      },
      {
          ITOK_TYPE_NONE,
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_INITIATOR_MIC,
          GSSEAP_STATE_INITIATOR_EXTS,
 -        0,
 -        eapGssSmInitCompleteInitiatorExts
 +        SM_ITOK_FLAG_REQUIRED,
 +        eapGssSmInitInitiatorMIC
      },
  #ifdef GSSEAP_ENABLE_REAUTH
      {
  #endif
      /* other extensions go here */
      {
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_ACCEPTOR_MIC,
          ITOK_TYPE_NONE,
          GSSEAP_STATE_ACCEPTOR_EXTS,
 -        0,
 -        eapGssSmInitCompleteAcceptorExts
 +        SM_ITOK_FLAG_REQUIRED,
 +        eapGssSmInitAcceptorMIC
      }
  };
  
@@@ -982,34 -942,24 +985,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;
  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))
diff --combined moonshot/mech_eap/util.h
@@@ -76,7 -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 +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 +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)
  {
@@@ -177,17 -191,12 +191,17 @@@ enum gss_eap_token_type 
  #define ITOK_TYPE_REAUTH_RESP           0x00000009 /* optional */
  #define ITOK_TYPE_VERSION_INFO          0x0000000A /* optional */
  #define ITOK_TYPE_VENDOR_INFO           0x0000000B /* optional */
 +#define ITOK_TYPE_GSS_FLAGS             0x0000000C /* optional */
 +#define ITOK_TYPE_INITIATOR_MIC         0x0000000D /* critical, required, if not reauth */
 +#define ITOK_TYPE_ACCEPTOR_MIC          0x0000000E /* TBD */
  
  #define ITOK_FLAG_CRITICAL              0x80000000  /* critical, wire flag */
  #define ITOK_FLAG_VERIFIED              0x40000000  /* verified, API flag */
  
  #define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
  
 +#define GSSEAP_WIRE_FLAGS_MASK          GSS_C_MUTUAL_FLAG
 +
  OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
  OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
  
@@@ -210,24 -219,16 +224,26 @@@ gssEapContextTime(OM_uint32 *minor
                    gss_ctx_id_t context_handle,
                    OM_uint32 *time_rec);
  
 +OM_uint32
 +gssEapMakeTokenMIC(OM_uint32 *minor,
 +                   gss_ctx_id_t ctx,
 +                   gss_buffer_t tokenMIC);
 +
 +OM_uint32
 +gssEapVerifyTokenMIC(OM_uint32 *minor,
 +                     gss_ctx_id_t ctx,
 +                     const gss_buffer_t tokenMIC);
 +
  /* util_cred.c */
  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,
                    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
@@@ -472,6 -489,17 +504,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
@@@ -653,29 -681,16 +696,29 @@@ voi
  gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
  
  /* util_token.c */
 +struct gss_eap_token_buffer_set {
 +    gss_buffer_set_desc buffers; /* pointers only */
 +    OM_uint32 *types;
 +};
 +
  OM_uint32
  gssEapEncodeInnerTokens(OM_uint32 *minor,
 -                        gss_buffer_set_t extensions,
 -                        OM_uint32 *types,
 +                        struct gss_eap_token_buffer_set *tokens,
                          gss_buffer_t buffer);
  OM_uint32
  gssEapDecodeInnerTokens(OM_uint32 *minor,
                          const gss_buffer_t buffer,
 -                        gss_buffer_set_t *pExtensions,
 -                        OM_uint32 **pTypes);
 +                        struct gss_eap_token_buffer_set *tokens);
 +
 +OM_uint32
 +gssEapReleaseInnerTokens(OM_uint32 *minor,
 +                         struct gss_eap_token_buffer_set *tokens,
 +                         int freeBuffers);
 +
 +OM_uint32
 +gssEapAllocInnerTokens(OM_uint32 *minor,
 +                       size_t count,
 +                       struct gss_eap_token_buffer_set *tokens);
  
  size_t
  tokenSize(const gss_OID_desc *mech, size_t body_size);
@@@ -70,7 -70,8 +70,7 @@@ gssEapAllocContext(OM_uint32 *minor
                      GSS_C_INTEG_FLAG    |   /* integrity */
                      GSS_C_CONF_FLAG     |   /* confidentiality */
                      GSS_C_SEQUENCE_FLAG |   /* sequencing */
 -                    GSS_C_REPLAY_FLAG|      /* replay detection */
 -      GSS_C_MUTUAL_FLAG; /*xxx big hack */
 +                    GSS_C_REPLAY_FLAG;      /* replay detection */
  
      *pCtx = ctx;
  
@@@ -129,7 -130,7 +129,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);
  
@@@ -227,149 -228,3 +227,149 @@@ gssEapContextTime(OM_uint32 *minor
  
      return GSS_S_COMPLETE;
  }
 +
 +static OM_uint32
 +gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
 +                           gss_ctx_id_t ctx,
 +                           gss_buffer_t tokenMIC,
 +                           int verifyMIC)
 +{
 +    OM_uint32 major;
 +    gss_iov_buffer_desc *iov = NULL;
 +    size_t i = 0, j;
 +    enum gss_eap_token_type tokType;
 +    OM_uint32 micTokType;
 +    unsigned char wireTokType[2];
 +    unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
 +    const struct gss_eap_token_buffer_set *tokens;
 +
 +    tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
 +
 +    assert(tokens != NULL);
 +
 +    iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
 +    if (iov == NULL) {
 +        major = GSS_S_FAILURE;
 +        *minor = ENOMEM;
 +        goto cleanup;
 +    }
 +
 +    innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
 +    if (innerTokTypes == NULL) {
 +        *minor = ENOMEM;
 +        major = GSS_S_FAILURE;
 +        goto cleanup;
 +    }
 +
 +    innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
 +    if (innerTokLengths == NULL) {
 +        major = GSS_S_FAILURE;
 +        *minor = ENOMEM;
 +        goto cleanup;
 +    }
 +
 +    /* Mechanism OID */
 +    assert(ctx->mechanismUsed != GSS_C_NO_OID);
 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
 +    iov[i].buffer.length = ctx->mechanismUsed->length;
 +    iov[i].buffer.value = ctx->mechanismUsed->elements;
 +    i++;
 +
 +    /* Token type */
 +    if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
 +        tokType = TOK_TYPE_INITIATOR_CONTEXT;
 +        micTokType = ITOK_TYPE_INITIATOR_MIC;
 +    } else {
 +        tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
 +        micTokType = ITOK_TYPE_ACCEPTOR_MIC;
 +    }
 +    store_uint16_be(tokType, wireTokType);
 +
 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
 +    iov[i].buffer.length = sizeof(wireTokType);
 +    iov[i].buffer.value = wireTokType;
 +    i++;
 +
 +    for (j = 0; j < tokens->buffers.count; j++) {
 +        if (verifyMIC &&
 +            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
 +            continue; /* will use this slot for trailer */
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
 +        iov[i].buffer.length = 4;
 +        iov[i].buffer.value = &innerTokTypes[j * 4];
 +        store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
 +                        iov[i].buffer.value);
 +        i++;
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
 +        iov[i].buffer.length = 4;
 +        iov[i].buffer.value = &innerTokLengths[j * 4];
 +        store_uint32_be(tokens->buffers.elements[j].length,
 +                        iov[i].buffer.value);
 +        i++;
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
 +        iov[i].buffer = tokens->buffers.elements[j];
 +        i++;
 +    }
 +
 +    if (verifyMIC) {
 +        assert(tokenMIC->length >= 16);
 +
 +        assert(i < 2 + (3 * tokens->buffers.count));
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
 +        iov[i].buffer.length = 16;
 +        iov[i].buffer.value = tokenMIC->value;
 +        i++;
 +
 +        iov[i].type = GSS_IOV_BUFFER_TYPE_TRAILER;
 +        iov[i].buffer.length = tokenMIC->length - 16;
 +        iov[i].buffer.value = (unsigned char *)tokenMIC->value + 16;
 +        i++;
 +
 +        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
 +                                        iov, i, TOK_TYPE_MIC);
 +    } else {
 +        iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
 +        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
 +                                   iov, i, TOK_TYPE_MIC);
 +        if (!GSS_ERROR(major))
 +            *tokenMIC = iov[i - 1].buffer;
 +    }
 +
 +cleanup:
 +    if (iov != NULL)
 +        gssEapReleaseIov(iov, tokens->buffers.count);
 +    if (innerTokTypes != NULL)
 +        GSSEAP_FREE(innerTokTypes);
 +    if (innerTokLengths != NULL)
 +        GSSEAP_FREE(innerTokLengths);
 +
 +    return major;
 +}
 +
 +OM_uint32
 +gssEapMakeTokenMIC(OM_uint32 *minor,
 +                   gss_ctx_id_t ctx,
 +                   gss_buffer_t tokenMIC)
 +{
 +    tokenMIC->length = 0;
 +    tokenMIC->value = NULL;
 +
 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE);
 +}
 +
 +OM_uint32
 +gssEapVerifyTokenMIC(OM_uint32 *minor,
 +                     gss_ctx_id_t ctx,
 +                     const gss_buffer_t tokenMIC)
 +{
 +    if (tokenMIC->length < 16) {
 +        *minor = GSSEAP_TOK_TRUNC;
 +        return GSS_S_BAD_SIG;
 +    }
 +
 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
 +}