Merge branch 'master' into tlv-mic
authorLuke Howard <lukeh@padl.com>
Sun, 15 May 2011 15:26:36 +0000 (17:26 +0200)
committerLuke Howard <lukeh@padl.com>
Sun, 15 May 2011 15:26:36 +0000 (17:26 +0200)
1  2 
moonshot/mech_eap/accept_sec_context.c
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/mech_eap.exports
moonshot/mech_eap/util.h

@@@ -131,49 -131,6 +131,49 @@@ acceptReadyEap(OM_uint32 *minor, gss_ct
  }
  
  static OM_uint32
 +gssEapSupportedInitiatorExts[] = {
 +};
 +
 +static struct gss_eap_itok_map
 +gssEapAcceptorExtsFlagMap[] = {
 +    { ITOK_TYPE_REAUTH_CREDS, CTX_FLAG_KRB_REAUTH_SUPPORTED },
 +};
 +
 +static OM_uint32
 +eapGssSmAcceptExts(OM_uint32 *minor,
 +                   gss_cred_id_t cred GSSEAP_UNUSED,
 +                   gss_ctx_id_t ctx GSSEAP_UNUSED,
 +                   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,
 +                   OM_uint32 *smFlags GSSEAP_UNUSED)
 +{
 +    OM_uint32 major;
 +
 +    major = gssEapProcessSupportedExts(minor, inputToken,
 +                                       gssEapAcceptorExtsFlagMap,
 +                                        sizeof(gssEapAcceptorExtsFlagMap) /
 +                                       sizeof(gssEapAcceptorExtsFlagMap[0]),
 +                                       &ctx->flags);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    major = gssEapEncodeSupportedExts(minor,
 +                                      gssEapSupportedInitiatorExts,
 +                                      sizeof(gssEapSupportedInitiatorExts) /
 +                                        sizeof(gssEapSupportedInitiatorExts[0]),
 +                                      outputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    return GSS_S_CONTINUE_NEEDED;
 +}
 +
 +static OM_uint32
  eapGssSmAcceptAcceptorName(OM_uint32 *minor,
                             gss_cred_id_t cred GSSEAP_UNUSED,
                             gss_ctx_id_t ctx,
@@@ -274,7 -231,7 +274,7 @@@ eapGssSmAcceptIdentity(OM_uint32 *minor
      GSSEAP_SM_TRANSITION_NEXT(ctx);
  
      *minor = 0;
 -    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 +    *smFlags |= SM_FLAG_SEND_TOKEN | SM_FLAG_OUTPUT_TOKEN_CRITICAL;
  
      return GSS_S_CONTINUE_NEEDED;
  }
@@@ -639,7 -596,7 +639,7 @@@ eapGssSmAcceptAuthenticate(OM_uint32 *m
  
      major = GSS_S_CONTINUE_NEEDED;
      *minor = 0;
 -    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 +    *smFlags |= SM_FLAG_SEND_TOKEN | SM_FLAG_OUTPUT_TOKEN_CRITICAL;
  
  cleanup:
      if (request != NULL)
  }
  
  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,
      OM_uint32 major, tmpMinor;
      gss_iov_buffer_desc iov[2];
  
 +    assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
 +
      iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
      iov[0].buffer.length = 0;
      iov[0].buffer.value = NULL;
@@@ -756,39 -677,29 +756,39 @@@ eapGssSmAcceptReauthCreds(OM_uint32 *mi
       * If we're built with fast reauthentication enabled, then
       * fabricate a ticket from the initiator to ourselves.
       */
 -    major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
 +    if (ctx->flags & CTX_FLAG_KRB_REAUTH_SUPPORTED)
 +        major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
 +    else
 +        major = GSS_S_UNAVAILABLE;
 +
      if (major == GSS_S_UNAVAILABLE)
          major = GSS_S_COMPLETE;
 -    if (major == GSS_S_COMPLETE)
 -        major = GSS_S_CONTINUE_NEEDED;
  
 -    return major;
 +    return GSS_ERROR(major) ? major : GSS_S_CONTINUE_NEEDED;
  }
  #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)
 +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;
 +
 +    assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
 +
 +    major = gssEapVerifyConversationMIC(minor, ctx, inputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
      GSSEAP_SM_TRANSITION_NEXT(ctx);
  
      *minor = 0;
  }
  
  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)
 +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)
  {
 +    OM_uint32 major;
 +
 +    major = gssEapGetConversationMIC(minor, ctx, outputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
      GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
  
      *minor = 0;
 -    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 +    *smFlags |= SM_FLAG_SEND_TOKEN | SM_FLAG_OUTPUT_TOKEN_CRITICAL;
  
      return GSS_S_COMPLETE;
  }
  
 +/*
 + * Acceptor state machine.
 + */
  static struct gss_eap_sm eapGssAcceptorSm[] = {
 +#ifdef GSSEAP_ENABLE_REAUTH
 +    {
 +        ITOK_TYPE_REAUTH_REQ,
 +        ITOK_TYPE_REAUTH_RESP,
 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
 +        0,
 +        eapGssSmAcceptGssReauth,
 +    },
 +#endif
      {
          ITOK_TYPE_ACCEPTOR_NAME_REQ,
          ITOK_TYPE_ACCEPTOR_NAME_RESP,
          0,
          eapGssSmAcceptAcceptorName
      },
 -#ifdef GSSEAP_DEBUG
      {
 -        ITOK_TYPE_VENDOR_INFO,
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_SUPPORTED_ACCEPTOR_EXTS,
 +        ITOK_TYPE_SUPPORTED_INITIATOR_EXTS,
          GSSEAP_STATE_INITIAL,
          0,
 -        eapGssSmAcceptVendorInfo,
 +        eapGssSmAcceptExts,
      },
 -#endif
 -#ifdef GSSEAP_ENABLE_REAUTH
 +#ifdef GSSEAP_DEBUG
      {
 -        ITOK_TYPE_REAUTH_REQ,
 -        ITOK_TYPE_REAUTH_RESP,
 +        ITOK_TYPE_VENDOR_INFO,
 +        ITOK_TYPE_NONE,
          GSSEAP_STATE_INITIAL,
          0,
 -        eapGssSmAcceptGssReauth,
 +        eapGssSmAcceptVendorInfo,
      },
  #endif
      {
          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,
 -        SM_ITOK_FLAG_REQUIRED,
 +        0,
          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
      },
  };
  
@@@ -955,6 -843,7 +955,7 @@@ gss_accept_sec_context(OM_uint32 *minor
          if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
              major = gssEapAcquireCred(minor,
                                        GSS_C_NO_NAME,
+                                       GSS_C_NO_OID,
                                        GSS_C_NO_BUFFER,
                                        GSS_C_INDEFINITE,
                                        GSS_C_NO_OID_SET,
@@@ -1064,7 -953,7 +1065,7 @@@ eapGssSmAcceptGssReauth(OM_uint32 *mino
                          gss_OID mech,
                          OM_uint32 reqFlags GSSEAP_UNUSED,
                          OM_uint32 timeReq GSSEAP_UNUSED,
 -                        gss_channel_bindings_t chanBindings,
 +                        gss_channel_bindings_t userChanBindings,
                          gss_buffer_t inputToken,
                          gss_buffer_t outputToken,
                          OM_uint32 *smFlags)
      OM_uint32 major, tmpMinor;
      gss_name_t krbInitiator = GSS_C_NO_NAME;
      OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
 +    struct gss_channel_bindings_struct wireChanBindings = { 0 };
  
      /*
       * If we're built with fast reauthentication support, it's valid
  
      ctx->flags |= CTX_FLAG_KRB_REAUTH;
  
 +    /*
 +     * To avoid an additional round trip, we use GSS channel bindings
 +     * to integrity protect the rest of the initiator exchange. This
 +     * does have the disadvantage of making it impossible for the
 +     * acceptor to ignore application channel bindings, behaviour
 +     * which differs from normal Kerberos and GSS-EAP itself.
 +     */
 +    major = gssEapMakeTokenChannelBindings(minor, ctx,
 +                                           userChanBindings,
 +                                           inputToken,
 +                                           &wireChanBindings);
 +    if (GSS_ERROR(major))
 +        return major;
 +
      major = gssAcceptSecContext(minor,
                                  &ctx->reauthCtx,
                                  cred->reauthCred,
                                  inputToken,
 -                                chanBindings,
 +                                &wireChanBindings,
                                  &krbInitiator,
                                  &mech,
                                  outputToken,
          major = acceptReadyKrb(minor, ctx, cred,
                                 krbInitiator, mech, timeRec);
          if (major == GSS_S_COMPLETE) {
 -            GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
 +            /* Generate acceptor MIC */
 +            GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ACCEPTOR_EXTS);
          }
          ctx->gssFlags = gssFlags;
      } else if (GSS_ERROR(major) &&
          (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) {
 -        /* pretend reauthentication attempt never happened */
 +        /* Fall back to EAP */
          gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
          ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
          GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
 -        major = GSS_S_CONTINUE_NEEDED;
 +    } else {
 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
      }
  
 +    major = GSS_S_CONTINUE_NEEDED;
 +
      gssReleaseName(&tmpMinor, &krbInitiator);
 +    gss_release_buffer(&tmpMinor, &wireChanBindings.application_data);
  
      return major;
  }
@@@ -223,11 -223,7 +223,11 @@@ peerConfigInit(OM_uint32 *minor
  
      assert(cred->name != GSS_C_NO_NAME);
  
 -    if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
 +    /*
 +     * draft-ietf-abfab-gss-eap-01: the host portion is empty
 +     * for initiators.
 +     */
 +    if ((cred->name->flags & NAME_FLAG_NAI) == 0) {
          *minor = GSSEAP_BAD_INITIATOR_NAME;
          return GSS_S_BAD_NAME;
      }
@@@ -447,31 -443,21 +447,31 @@@ eapGssSmInitGssReauth(OM_uint32 *minor
                        gss_OID mech GSSEAP_UNUSED,
                        OM_uint32 reqFlags,
                        OM_uint32 timeReq,
 -                      gss_channel_bindings_t chanBindings,
 +                      gss_channel_bindings_t userChanBindings,
                        gss_buffer_t inputToken,
                        gss_buffer_t outputToken,
 -                      OM_uint32 *smFlags GSSEAP_UNUSED)
 +                      OM_uint32 *smFlags)
  {
      OM_uint32 major, tmpMinor;
      gss_name_t mechTarget = GSS_C_NO_NAME;
      gss_OID actualMech = GSS_C_NO_OID;
      OM_uint32 gssFlags, timeRec;
 +    struct gss_channel_bindings_struct wireChanBindings = { 0 };
  
      assert(cred != GSS_C_NO_CREDENTIAL);
  
      if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
 -        if (!gssEapCanReauthP(cred, target, timeReq))
 -            return GSS_S_CONTINUE_NEEDED;
 +        if (!gssEapCanReauthP(cred, target, timeReq)) {
 +            major = GSS_S_CONTINUE_NEEDED;
 +            goto cleanup;
 +        }
 +
 +        major = gssEapMakeTokenChannelBindings(minor, ctx,
 +                                               userChanBindings,
 +                                               GSS_C_NO_BUFFER,
 +                                               &wireChanBindings);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
  
          ctx->flags |= CTX_FLAG_KRB_REAUTH;
      } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
                                (gss_OID)gss_mech_krb5,
                                reqFlags | GSS_C_MUTUAL_FLAG,
                                timeReq,
 -                              chanBindings,
 +                              &wireChanBindings,
                                inputToken,
                                &actualMech,
                                outputToken,
          major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
          if (GSS_ERROR(major))
              goto cleanup;
 -        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
 +
 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ACCEPTOR_EXTS);
      } else {
          GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
 +        *smFlags |= SM_FLAG_SEND_TOKEN;
      }
  
 +    major = GSS_S_CONTINUE_NEEDED;
 +
  cleanup:
      gssReleaseName(&tmpMinor, &mechTarget);
 +    gss_release_buffer(&tmpMinor, &wireChanBindings.application_data);
  
      return major;
  }
@@@ -596,50 -577,6 +596,50 @@@ eapGssSmInitAcceptorName(OM_uint32 *min
  }
  
  static OM_uint32
 +gssEapSupportedAcceptorExts[] = {
 +    ITOK_TYPE_REAUTH_CREDS,
 +};
 +
 +static struct gss_eap_itok_map
 +gssEapInitiatorExtsFlagMap[] = {
 +};
 +
 +static OM_uint32
 +eapGssSmInitExts(OM_uint32 *minor,
 +                 gss_cred_id_t cred GSSEAP_UNUSED,
 +                 gss_ctx_id_t ctx GSSEAP_UNUSED,
 +                 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,
 +                 OM_uint32 *smFlags GSSEAP_UNUSED)
 +{
 +    OM_uint32 major = GSS_S_COMPLETE;
 +
 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
 +        major = gssEapEncodeSupportedExts(minor,
 +                                          gssEapSupportedAcceptorExts,
 +                                          sizeof(gssEapSupportedAcceptorExts) /
 +                                            sizeof(gssEapSupportedAcceptorExts[0]),
 +                                          outputToken);
 +    } else if (inputToken != GSS_C_NO_BUFFER) {
 +        major = gssEapProcessSupportedExts(minor, inputToken,
 +                                          gssEapInitiatorExtsFlagMap,
 +                                          sizeof(gssEapInitiatorExtsFlagMap) /
 +                                            sizeof(gssEapInitiatorExtsFlagMap[0]),
 +                                          &ctx->flags);
 +    }
 +
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    return GSS_S_CONTINUE_NEEDED;
 +}
 +
 +static OM_uint32
  eapGssSmInitIdentity(OM_uint32 *minor,
                       gss_cred_id_t cred GSSEAP_UNUSED,
                       gss_ctx_id_t ctx,
          GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
      } else
  #endif
 -        *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 +        *smFlags |= SM_FLAG_SEND_TOKEN;
  
      assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
      assert(inputToken == GSS_C_NO_BUFFER);
@@@ -768,7 -705,7 +768,7 @@@ cleanup
              *minor = tmpMinor;
          }
  
 -        *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 +        *smFlags |= SM_FLAG_SEND_TOKEN | SM_FLAG_OUTPUT_TOKEN_CRITICAL;
      }
  
      wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
  }
  
  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,
                                 gss_channel_bindings_t chanBindings,
                                 gss_buffer_t inputToken GSSEAP_UNUSED,
                                 gss_buffer_t outputToken,
 -                               OM_uint32 *smFlags)
 +                               OM_uint32 *smFlags GSSEAP_UNUSED)
  {
      OM_uint32 major;
 -    gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
  
 -    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
 -        buffer = chanBindings->application_data;
 -
 -    major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
 -                       &buffer, NULL, outputToken);
 -    if (GSS_ERROR(major))
 -        return major;
 -
 -    assert(outputToken->value != NULL);
 +    if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0 &&
 +        chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
 +        major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
 +                           &chanBindings->application_data, NULL, outputToken);
 +        if (GSS_ERROR(major))
 +            return major;
 +    }
  
      *minor = 0;
 -    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 -
      return GSS_S_CONTINUE_NEEDED;
  }
  
@@@ -856,51 -774,39 +856,51 @@@ eapGssSmInitReauthCreds(OM_uint32 *mino
  #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)
 +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 = gssEapGetConversationMIC(minor, ctx, outputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
      GSSEAP_SM_TRANSITION_NEXT(ctx);
  
      *minor = 0;
 -    *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
 +    *smFlags |= SM_FLAG_SEND_TOKEN | SM_FLAG_OUTPUT_TOKEN_CRITICAL;
  
      return GSS_S_CONTINUE_NEEDED;
  }
  
  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)
 +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)
  {
 +    OM_uint32 major;
 +
 +    major = gssEapVerifyConversationMIC(minor, ctx, inputToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
      GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
  
      *minor = 0;
      return GSS_S_COMPLETE;
  }
  
 +/*
 + * Initiator state machine.
 + */
  static struct gss_eap_sm eapGssInitiatorSm[] = {
      {
          ITOK_TYPE_CONTEXT_ERR,
          0,
          eapGssSmInitAcceptorName
      },
 +    {
 +        ITOK_TYPE_SUPPORTED_INITIATOR_EXTS,
 +        ITOK_TYPE_SUPPORTED_ACCEPTOR_EXTS,
 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
 +        0,
 +        eapGssSmInitExts
 +    },
  #ifdef GSSEAP_DEBUG
      {
          ITOK_TYPE_NONE,
      },
      {
          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,
 +        0,
          eapGssSmInitGssChannelBindings
      },
      {
          ITOK_TYPE_NONE,
 -        ITOK_TYPE_NONE,
 +        ITOK_TYPE_INITIATOR_MIC,
          GSSEAP_STATE_INITIATOR_EXTS,
          0,
 -        eapGssSmInitCompleteInitiatorExts
 +        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
      }
  };
  
@@@ -1054,6 -943,7 +1054,7 @@@ gss_init_sec_context(OM_uint32 *minor
          if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
              major = gssEapAcquireCred(minor,
                                        GSS_C_NO_NAME,
+                                       GSS_C_NO_OID,
                                        GSS_C_NO_BUFFER,
                                        time_req,
                                        GSS_C_NO_OID_SET,
@@@ -1,8 -1,8 +1,9 @@@
  gss_accept_sec_context
  gss_acquire_cred
+ gss_acquire_cred_ext
  gss_add_cred
  gss_add_cred_with_password
 +gss_authorize_localname
  gss_canonicalize_name
  gss_compare_name
  gss_context_time
@@@ -23,6 -23,7 +24,7 @@@ gss_init_sec_contex
  gss_inquire_attrs_for_mech
  gss_inquire_context
  gss_inquire_cred
+ gss_inquire_cred_by_mech
  gss_inquire_cred_by_oid
  gss_inquire_mechs_for_name
  gss_inquire_mech_for_saslname
diff --combined moonshot/mech_eap/util.h
@@@ -164,74 -164,58 +164,77 @@@ enum gss_eap_token_type 
      TOK_TYPE_ACCEPTOR_CONTEXT        = 0x0602,  /* acceptor-sent context token */
  };
  
 +struct gss_eap_itok_map {
 +    OM_uint32 type;                             /* inner token type */
 +    OM_uint32 flag;                             /* context flag */
 +};
 +
  /* inner token types and flags */
 -#define ITOK_TYPE_NONE                  0x00000000
 -#define ITOK_TYPE_CONTEXT_ERR           0x00000001 /* critical */
 -#define ITOK_TYPE_ACCEPTOR_NAME_REQ     0x00000002 /* TBD */
 -#define ITOK_TYPE_ACCEPTOR_NAME_RESP    0x00000003 /* TBD */
 -#define ITOK_TYPE_EAP_RESP              0x00000004 /* critical, required, if not reauth */
 -#define ITOK_TYPE_EAP_REQ               0x00000005 /* critical, required, if not reauth */
 -#define ITOK_TYPE_GSS_CHANNEL_BINDINGS  0x00000006 /* critical, required, if not reauth */
 -#define ITOK_TYPE_REAUTH_CREDS          0x00000007 /* optional */
 -#define ITOK_TYPE_REAUTH_REQ            0x00000008 /* optional */
 -#define ITOK_TYPE_REAUTH_RESP           0x00000009 /* optional */
 -#define ITOK_TYPE_VERSION_INFO          0x0000000A /* optional */
 -#define ITOK_TYPE_VENDOR_INFO           0x0000000B /* optional */
 -
 -#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 ITOK_TYPE_NONE                      0x00000000
 +#define ITOK_TYPE_CONTEXT_ERR               0x00000001 /* critical */
 +#define ITOK_TYPE_ACCEPTOR_NAME_REQ         0x00000002 /* TBD */
 +#define ITOK_TYPE_ACCEPTOR_NAME_RESP        0x00000003 /* TBD */
 +#define ITOK_TYPE_EAP_RESP                  0x00000004 /* critical, required, if not reauth */
 +#define ITOK_TYPE_EAP_REQ                   0x00000005 /* critical, required, if not reauth */
 +#define ITOK_TYPE_GSS_CHANNEL_BINDINGS      0x00000006 /* optional */
 +#define ITOK_TYPE_REAUTH_CREDS              0x00000007 /* optional */
 +#define ITOK_TYPE_REAUTH_REQ                0x00000008 /* optional */
 +#define ITOK_TYPE_REAUTH_RESP               0x00000009 /* optional */
 +#define ITOK_TYPE_GSS_FLAGS                 0x0000000A /* optional */
 +#define ITOK_TYPE_INITIATOR_MIC             0x0000000B /* required */
 +#define ITOK_TYPE_ACCEPTOR_MIC              0x0000000C /* required */
 +#define ITOK_TYPE_SUPPORTED_ACCEPTOR_EXTS   0x0000000D /* optional */
 +#define ITOK_TYPE_SUPPORTED_INITIATOR_EXTS  0x0000000E /* optional */
 +
 +/* experimental */
 +#define ITOK_TYPE_VERSION_INFO              0x00000080 /* optional */
 +#define ITOK_TYPE_VENDOR_INFO               0x00000081 /* optional */
 +
 +#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 ITOK_HEADER_LENGTH                  8           /* type || length */
 +
 +#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);
  
  OM_uint32
 -gssEapMakeToken(OM_uint32 *minor,
 -                gss_ctx_id_t ctx,
 -                const gss_buffer_t innerToken,
 -                enum gss_eap_token_type tokenType,
 -                gss_buffer_t outputToken);
 +gssEapContextTime(OM_uint32 *minor,
 +                  gss_ctx_id_t context_handle,
 +                  OM_uint32 *time_rec);
  
  OM_uint32
 -gssEapVerifyToken(OM_uint32 *minor,
 -                  gss_ctx_id_t ctx,
 -                  const gss_buffer_t inputToken,
 -                  enum gss_eap_token_type *tokenType,
 -                  gss_buffer_t innerInputToken);
 +gssEapGetConversationMIC(OM_uint32 *minor,
 +                         gss_ctx_id_t ctx,
 +                         gss_buffer_t convMIC);
  
  OM_uint32
 -gssEapContextTime(OM_uint32 *minor,
 -                  gss_ctx_id_t context_handle,
 -                  OM_uint32 *time_rec);
 +gssEapVerifyConversationMIC(OM_uint32 *minor,
 +                            gss_ctx_id_t ctx,
 +                            const gss_buffer_t convMIC);
 +
 +OM_uint32
 +gssEapMakeTokenChannelBindings(OM_uint32 *minor,
 +                               gss_ctx_id_t ctx,
 +                               gss_channel_bindings_t userBindings,
 +                               gss_buffer_t inputToken,
 +                               gss_channel_bindings_t wireBindings);
  
  /* util_cred.c */
+ extern const gss_OID_desc gssEapPasswordCredType;
  OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
  OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
  
  OM_uint32
  gssEapAcquireCred(OM_uint32 *minor,
                    const gss_name_t desiredName,
-                   const gss_buffer_t password,
+                   gss_const_OID credType,
+                   const void *credData,
                    OM_uint32 timeReq,
                    const gss_OID_set desiredMechs,
                    int cred_usage,
  
  int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
  
+ OM_uint32
+ gssEapInquireCred(OM_uint32 *minor,
+                   gss_cred_id_t cred,
+                   gss_name_t *name,
+                   OM_uint32 *pLifetime,
+                   gss_cred_usage_t *cred_usage,
+                   gss_OID_set *mechanisms);
  /* util_crypt.c */
  int
  gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
@@@ -623,7 -615,7 +634,7 @@@ struct gss_eap_sm 
  };
  
  /* state machine flags, set by handler */
 -#define SM_FLAG_FORCE_SEND_TOKEN            0x00000001  /* send token even if no inner tokens */
 +#define SM_FLAG_SEND_TOKEN                  0x00000001  /* exit state machine, send token */
  #define SM_FLAG_OUTPUT_TOKEN_CRITICAL       0x00000002  /* output token is critical */
  
  /* state machine flags, set by state machine */
@@@ -650,48 -642,24 +661,48 @@@ gssEapSmTransition(gss_ctx_id_t ctx, en
  
  /* util_token.c */
  OM_uint32
 -gssEapEncodeInnerTokens(OM_uint32 *minor,
 -                        gss_buffer_set_t extensions,
 -                        OM_uint32 *types,
 -                        gss_buffer_t buffer);
 -OM_uint32
  gssEapDecodeInnerTokens(OM_uint32 *minor,
                          const gss_buffer_t buffer,
                          gss_buffer_set_t *pExtensions,
                          OM_uint32 **pTypes);
  
 +OM_uint32
 +gssEapRecordContextTokenHeader(OM_uint32 *minor,
 +                               gss_ctx_id_t ctx,
 +                               enum gss_eap_token_type tokType);
 +
 +OM_uint32
 +gssEapRecordInnerContextToken(OM_uint32 *minor,
 +                              gss_ctx_id_t ctx,
 +                              gss_buffer_t innerToken,
 +                              OM_uint32 type);
 +
 +OM_uint32
 +gssEapVerifyContextToken(OM_uint32 *minor,
 +                         gss_ctx_id_t ctx,
 +                         const gss_buffer_t inputToken,
 +                         enum gss_eap_token_type tokenType,
 +                         gss_buffer_t innerInputToken);
 +
 +OM_uint32
 +gssEapEncodeSupportedExts(OM_uint32 *minor,
 +                          OM_uint32 *types,
 +                          size_t typesCount,
 +                          gss_buffer_t outputToken);
 +
 +OM_uint32
 +gssEapProcessSupportedExts(OM_uint32 *minor,
 +                           gss_buffer_t inputToken,
 +                           struct gss_eap_itok_map *map,
 +                           size_t mapCount,
 +                           OM_uint32 *flags);
 +
  size_t
 -tokenSize(const gss_OID_desc *mech, size_t body_size);
 +tokenSize(size_t bodySize);
  
  void
 -makeTokenHeader(const gss_OID_desc *mech,
 -                size_t body_size,
 -                unsigned char **buf,
 -                enum gss_eap_token_type tok_type);
 +makeTokenHeader(size_t body_size,
 +                unsigned char **buf);
  
  OM_uint32
  verifyTokenHeader(OM_uint32 *minor,