Merge branch 'master' into tlv-mic
authorLuke Howard <lukeh@padl.com>
Mon, 4 Apr 2011 15:43:07 +0000 (01:43 +1000)
committerLuke Howard <lukeh@padl.com>
Mon, 4 Apr 2011 15:43:07 +0000 (01:43 +1000)
Conflicts:
mech_eap/util_saml.cpp

1  2 
mech_eap/accept_sec_context.c

@@@ -121,54 -121,16 +121,59 @@@ acceptReadyEap(OM_uint32 *minor, gss_ct
      if (GSS_ERROR(major))
          return major;
  
+     if (ctx->expiryTime < time(NULL)) {
+         *minor = GSSEAP_CRED_EXPIRED;
+         return GSS_S_CREDENTIALS_EXPIRED;
+     }
      *minor = 0;
      return GSS_S_COMPLETE;
  }
  
  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,
@@@ -269,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;
  }
@@@ -634,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;
@@@ -751,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
      },
  };
  
@@@ -1059,7 -952,7 +1064,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->kerberosCtx,
                                  cred->krbCred,
                                  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->kerberosCtx, 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;
  }