preliminary work on fast reauth
authorLuke Howard <lukeh@padl.com>
Wed, 22 Sep 2010 21:58:24 +0000 (23:58 +0200)
committerLuke Howard <lukeh@padl.com>
Wed, 22 Sep 2010 21:58:24 +0000 (23:58 +0200)
mech_eap/accept_sec_context.c
mech_eap/eap_mech.c
mech_eap/gssapiP_eap.h
mech_eap/init_sec_context.c
mech_eap/util.h
mech_eap/util_context.c
mech_eap/util_cred.c
mech_eap/util_reauth.c
mech_eap/util_reauth.h [new file with mode: 0644]
mech_eap/util_token.c

index 981a7d8..a3a09ee 100644 (file)
 
 #include "gssapiP_eap.h"
 
+static OM_uint32
+acceptReadyCommon(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
+{
+    OM_uint32 major;
+
+    major = sequenceInit(minor,
+                         &ctx->seqState, ctx->recvSeq,
+                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+                         TRUE);
+    if (GSS_ERROR(major))
+        return major;
+
+    return GSS_S_COMPLETE;
+}
+
+
 /*
  * Mark a context as ready for cryptographic operations
  */
 static OM_uint32
-acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
+acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
 {
     OM_uint32 major, tmpMinor;
     VALUE_PAIR *vp;
@@ -91,15 +108,7 @@ acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
         ctx->encryptionType = ENCTYPE_NULL;
     }
 
-    major = sequenceInit(minor,
-                         &ctx->seqState, ctx->recvSeq,
-                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
-                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
-                         TRUE);
-    if (GSS_ERROR(major))
-        return major;
-
-    return GSS_S_COMPLETE;
+    return acceptReadyCommon(minor, ctx, cred);
 }
 
 static OM_uint32
@@ -322,7 +331,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
         ctx->acceptorCtx.avps = received;
         received = NULL;
 
-        major = acceptReady(minor, ctx, cred);
+        major = acceptReadyEap(minor, ctx, cred);
         if (GSS_ERROR(major))
             goto cleanup;
 
@@ -352,56 +361,55 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
     outputToken->length = 0;
     outputToken->value = NULL;
 
-    if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS) {
-        ctx->state = EAP_STATE_ESTABLISHED;
-        return GSS_S_COMPLETE;
-    }
-
-    if (inputToken->length < 14) {
-        return GSS_S_DEFECTIVE_TOKEN;
-    }
+    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
+        if (inputToken->length < 14) {
+            return GSS_S_DEFECTIVE_TOKEN;
+        }
 
-    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
-    iov[0].buffer.length = 0;
-    iov[0].buffer.value = NULL;
+        iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+        iov[0].buffer.length = 0;
+        iov[0].buffer.value = NULL;
 
-    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
-        iov[0].buffer = chanBindings->application_data;
+        if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
+            iov[0].buffer = chanBindings->application_data;
 
-    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
-    iov[1].buffer.length = 16;
-    iov[1].buffer.value = (unsigned char *)inputToken->value - 2;
+        iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
+        iov[1].buffer.length = 16;
+        iov[1].buffer.value = (unsigned char *)inputToken->value - 2;
 
-    assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB);
+        assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB);
 
-    iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
-    iov[2].buffer.length = inputToken->length - 14;
-    iov[2].buffer.value = (unsigned char *)inputToken->value + 14;
+        iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+        iov[2].buffer.length = inputToken->length - 14;
+        iov[2].buffer.value = (unsigned char *)inputToken->value + 14;
 
-    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
-                                    iov, 3, TOK_TYPE_GSS_CB);
-    if (major == GSS_S_COMPLETE) {
-        ctx->state = EAP_STATE_ESTABLISHED;
+        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+                                        iov, 3, TOK_TYPE_GSS_CB);
+        if (GSS_ERROR(major))
+            return major;
     }
 
-#if 0
-    gss_release_buffer(&tmpMinor, &iov[0].buffer);
-#endif
-
-    return major;
+    ctx->state = EAP_STATE_KRB_REAUTH_CRED;
+    return GSS_S_CONTINUE_NEEDED;
 }
 
 static OM_uint32
-eapGssSmAcceptKrbCred(OM_uint32 *minor,
-                      gss_ctx_id_t ctx,
-                      gss_cred_id_t cred,
-                      gss_buffer_t inputToken,
-                      gss_channel_bindings_t chanBindings,
-                      gss_buffer_t outputToken)
+eapGssSmAcceptKrbReauthCred(OM_uint32 *minor,
+                            gss_ctx_id_t ctx,
+                            gss_cred_id_t cred,
+                            gss_buffer_t inputToken,
+                            gss_channel_bindings_t chanBindings,
+                            gss_buffer_t outputToken)
 {
-    /* Called with already established context */
-    *minor = EINVAL;
-    return GSS_S_BAD_STATUS;
+    OM_uint32 major;
+
+    major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    ctx->state = EAP_STATE_ESTABLISHED;
+
+    return GSS_S_COMPLETE;
 }
 
 static OM_uint32
@@ -417,6 +425,140 @@ eapGssSmAcceptEstablished(OM_uint32 *minor,
     return GSS_S_BAD_STATUS;
 }
 
+static OM_uint32
+acceptReadyKrb(OM_uint32 *minor,
+               gss_ctx_id_t ctx,
+               gss_cred_id_t cred,
+               const gss_name_t initiator,
+               const gss_OID mech,
+               OM_uint32 timeRec)
+{
+    OM_uint32 major, tmpMinor;
+    gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
+    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+
+    if (!oidEqual(mech, gss_mech_krb5)) {
+        major = GSS_S_BAD_MECH;
+        goto cleanup;
+    }
+
+    major = gssInquireSecContextByOid(minor, ctx->kerberosCtx,
+                                      GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    {
+        gss_OID_desc oid;
+        int suffix;
+
+        oid.length = keyData->elements[1].length;
+        oid.elements = keyData->elements[1].value;
+
+        /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
+        major = decomposeOid(minor,
+                             "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
+                             10, &oid, &suffix);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        ctx->encryptionType = suffix;
+    }
+
+    {
+        krb5_context krbContext = NULL;
+        krb5_keyblock key;
+
+        GSSEAP_KRB_INIT(&krbContext);
+
+        KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
+        KRB_KEY_DATA(&key)   = keyData->elements[0].value;
+        KRB_KEY_TYPE(&key)   = ctx->encryptionType;
+
+        *minor = krb5_copy_keyblock_contents(krbContext,
+                                             &key, &ctx->rfc3961Key);
+        if (*minor != 0) {
+            major = GSS_S_FAILURE;
+            goto cleanup;
+        }
+    }
+
+    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+                                      &ctx->checksumType);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssDisplayName(minor, initiator, &nameBuf, NULL);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+                             &ctx->initiatorName);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+        major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
+    if (timeRec != GSS_C_INDEFINITE)
+        ctx->expiryTime = time(NULL) + timeRec;
+
+    major = acceptReadyCommon(minor, ctx, cred);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    ctx->state = EAP_STATE_ESTABLISHED;
+    ctx->mechanismUsed = GSS_EAP_MECHANISM;
+
+cleanup:
+    gss_release_buffer_set(&tmpMinor, &keyData);
+    gss_release_buffer(&tmpMinor, &nameBuf);
+
+    return major;
+}
+
+static OM_uint32
+eapGssSmAcceptGssReauth(OM_uint32 *minor,
+                         gss_ctx_id_t ctx,
+                         gss_cred_id_t cred,
+                         gss_buffer_t inputToken,
+                         gss_channel_bindings_t chanBindings,
+                         gss_buffer_t outputToken)
+{
+    OM_uint32 major, tmpMinor;
+    gss_cred_id_t krbCred = GSS_C_NO_CREDENTIAL;
+    gss_name_t krbInitiator = GSS_C_NO_NAME;
+    gss_OID mech = GSS_C_NO_OID;
+    OM_uint32 timeRec = GSS_C_INDEFINITE;
+
+    ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
+
+    if (cred != GSS_C_NO_CREDENTIAL)
+        krbCred = cred->krbCred;
+
+    major = gssAcceptSecContext(minor,
+                                &ctx->kerberosCtx,
+                                krbCred,
+                                inputToken,
+                                chanBindings,
+                                &krbInitiator,
+                                &mech,
+                                outputToken,
+                                &ctx->gssFlags,
+                                &timeRec,
+                                NULL);
+    if (major == GSS_S_COMPLETE) {
+        major = acceptReadyKrb(minor, ctx, cred,
+                               krbInitiator, mech, timeRec);
+    }
+
+    gssReleaseName(&tmpMinor, &krbInitiator);
+
+    return major;
+}
+
 static struct gss_eap_acceptor_sm {
     enum gss_eap_token_type inputTokenType;
     enum gss_eap_token_type outputTokenType;
@@ -427,11 +569,12 @@ static struct gss_eap_acceptor_sm {
                               gss_channel_bindings_t,
                               gss_buffer_t);
 } eapGssAcceptorSm[] = {
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptIdentity           },
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptAuthenticate       },
-    { TOK_TYPE_GSS_CB,      TOK_TYPE_NONE,     eapGssSmAcceptGssChannelBindings },
-    { TOK_TYPE_NONE,        TOK_TYPE_KRB_CRED, eapGssSmAcceptKrbCred            },
-    { TOK_TYPE_NONE,        TOK_TYPE_NONE,     eapGssSmAcceptEstablished        },
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptIdentity           },
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptAuthenticate       },
+    { TOK_TYPE_GSS_CB,      TOK_TYPE_NONE,       eapGssSmAcceptGssChannelBindings },
+    { TOK_TYPE_NONE,        TOK_TYPE_KRB_CRED,   eapGssSmAcceptKrbReauthCred      },
+    { TOK_TYPE_NONE,        TOK_TYPE_NONE,       eapGssSmAcceptEstablished        },
+    { TOK_TYPE_GSS_REAUTH,  TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth          },
 };
 
 OM_uint32
@@ -453,6 +596,7 @@ gss_accept_sec_context(OM_uint32 *minor,
     struct gss_eap_acceptor_sm *sm = NULL;
     gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
+    enum gss_eap_token_type tokType;
 
     *minor = 0;
 
@@ -480,9 +624,13 @@ gss_accept_sec_context(OM_uint32 *minor,
     sm = &eapGssAcceptorSm[ctx->state];
 
     major = gssEapVerifyToken(minor, ctx, input_token,
-                              sm->inputTokenType, &innerInputToken);
-    if (GSS_ERROR(major))
+                              sm->inputTokenType, &tokType,
+                              &innerInputToken);
+    if (major == GSS_S_DEFECTIVE_TOKEN && tokType == TOK_TYPE_GSS_REAUTH) {
+        ctx->state = EAP_STATE_KRB_REAUTH_GSS;
+    } else if (GSS_ERROR(major)) {
         goto cleanup;
+    }
 
     /* If credentials were provided, check they're usable with this mech */
     if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
index ea43ad3..2f3081c 100644 (file)
@@ -284,6 +284,9 @@ gssEapInit(void)
 
     major = gssEapLocalAttrProviderInit(&minor);
     assert(major == GSS_S_COMPLETE);
+
+    major = gssEapReauthInitialize(&minor);
+    assert(major == GSS_S_COMPLETE);
 }
 
 static void
index 8fbbdb9..0d7809b 100644 (file)
@@ -42,6 +42,7 @@
 
 /* GSS includes */
 #include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
 #include <gssapi/gssapi_ext.h>
 #include "gssapi_eap.h"
 
@@ -96,6 +97,7 @@ struct gss_cred_id_struct {
 };
 
 #define CTX_FLAG_INITIATOR                  0x00000001
+#define CTX_FLAG_KRB_REAUTH_GSS             0x00000002
 
 #define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
 
@@ -103,8 +105,9 @@ enum gss_eap_state {
     EAP_STATE_IDENTITY = 0,
     EAP_STATE_AUTHENTICATE,
     EAP_STATE_GSS_CHANNEL_BINDINGS,
-    EAP_STATE_FAST_REAUTH,
-    EAP_STATE_ESTABLISHED
+    EAP_STATE_KRB_REAUTH_CRED,
+    EAP_STATE_ESTABLISHED,
+    EAP_STATE_KRB_REAUTH_GSS
 };
 
 #define CTX_IS_ESTABLISHED(ctx)             ((ctx)->state == EAP_STATE_ESTABLISHED)
@@ -156,6 +159,8 @@ struct gss_ctx_id_struct {
         #define initiatorCtx         ctxU.initiator
         struct gss_eap_acceptor_ctx  acceptor;
         #define acceptorCtx          ctxU.acceptor
+        gss_ctx_id_t                 kerberos;
+        #define kerberosCtx          ctxU.kerberos
     } ctxU;
 };
 
index 173f234..3303fd2 100644 (file)
@@ -480,8 +480,8 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
-    major = GSS_S_COMPLETE;
-    ctx->state = EAP_STATE_ESTABLISHED;
+    major = GSS_S_CONTINUE_NEEDED;
+    ctx->state = EAP_STATE_KRB_REAUTH_CRED;
 
 cleanup:
     gssEapReleaseIov(iov, 2);
@@ -490,20 +490,26 @@ cleanup:
 }
 
 static OM_uint32
-eapGssSmInitKrbCred(OM_uint32 *minor,
-                    gss_cred_id_t cred,
-                    gss_ctx_id_t ctx,
-                    gss_name_t target,
-                    gss_OID mech,
-                    OM_uint32 reqFlags,
-                    OM_uint32 timeReq,
-                    gss_channel_bindings_t chanBindings,
-                    gss_buffer_t inputToken,
-                    gss_buffer_t outputToken)
+eapGssSmInitKrbReauthCred(OM_uint32 *minor,
+                          gss_cred_id_t cred,
+                          gss_ctx_id_t ctx,
+                          gss_name_t target,
+                          gss_OID mech,
+                          OM_uint32 reqFlags,
+                          OM_uint32 timeReq,
+                          gss_channel_bindings_t chanBindings,
+                          gss_buffer_t inputToken,
+                          gss_buffer_t outputToken)
 {
-    /* Called with already established context */
-    *minor = EINVAL;
-    return GSS_S_BAD_STATUS;
+    OM_uint32 major;
+
+    major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    ctx->state = EAP_STATE_ESTABLISHED;
+
+    return GSS_S_COMPLETE;
 }
 
 static OM_uint32
@@ -540,7 +546,7 @@ static struct gss_eap_initiator_sm {
     { TOK_TYPE_NONE,    TOK_TYPE_EAP_RESP,  eapGssSmInitIdentity            },
     { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitAuthenticate        },
     { TOK_TYPE_NONE,    TOK_TYPE_GSS_CB,    eapGssSmInitGssChannelBindings  },
-    { TOK_TYPE_KRB_CRED,TOK_TYPE_NONE,      eapGssSmInitKrbCred             },
+    { TOK_TYPE_KRB_CRED,TOK_TYPE_NONE,      eapGssSmInitKrbReauthCred       },
     { TOK_TYPE_NONE,    TOK_TYPE_NONE,      eapGssSmInitEstablished         },
 };
 
@@ -565,6 +571,7 @@ gss_init_sec_context(OM_uint32 *minor,
     struct gss_eap_initiator_sm *sm = NULL;
     gss_buffer_desc innerInputToken;
     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
+    enum gss_eap_token_type tokType;
 
     *minor = 0;
 
@@ -595,7 +602,8 @@ gss_init_sec_context(OM_uint32 *minor,
 
     if (input_token != GSS_C_NO_BUFFER) {
         major = gssEapVerifyToken(minor, ctx, input_token,
-                                  sm->inputTokenType, &innerInputToken);
+                                  sm->inputTokenType,
+                                  &tokType, &innerInputToken);
         if (GSS_ERROR(major))
             goto cleanup;
     } else {
index c23c997..bc80e08 100644 (file)
@@ -172,6 +172,7 @@ gssEapVerifyToken(OM_uint32 *minor,
                   gss_ctx_id_t ctx,
                   const gss_buffer_t inputToken,
                   enum gss_eap_token_type tokenType,
+                  enum gss_eap_token_type *actualToken,
                   gss_buffer_t innerInputToken);
 
 OM_uint32
@@ -398,7 +399,8 @@ verifyTokenHeader(OM_uint32 *minor,
                   size_t *body_size,
                   unsigned char **buf_in,
                   size_t toksize_in,
-                  enum gss_eap_token_type tok_type);
+                  enum gss_eap_token_type tok_type,
+                  enum gss_eap_token_type *ret_tok_type);
 
 /* Helper macros */
 #define GSSEAP_CALLOC(count, size)      (calloc((count), (size)))
@@ -561,5 +563,6 @@ gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
 #endif
 
 #include "util_attr.h"
+#include "util_reauth.h"
 
 #endif /* _UTIL_H_ */
index a96b452..146b9a9 100644 (file)
@@ -106,7 +106,9 @@ gssEapReleaseContext(OM_uint32 *minor,
 
     gssEapKerberosInit(&tmpMinor, &krbContext);
 
-    if (CTX_IS_INITIATOR(ctx)) {
+    if (ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) {
+        gssDeleteSecContext(&tmpMinor, &ctx->kerberosCtx, GSS_C_NO_BUFFER);
+    } else if (CTX_IS_INITIATOR(ctx)) {
         releaseInitiatorContext(&ctx->initiatorCtx);
     } else {
         releaseAcceptorContext(&ctx->acceptorCtx);
@@ -157,6 +159,7 @@ gssEapVerifyToken(OM_uint32 *minor,
                   gss_ctx_id_t ctx,
                   const gss_buffer_t inputToken,
                   enum gss_eap_token_type tokenType,
+                  enum gss_eap_token_type *actualToken,
                   gss_buffer_t innerInputToken)
 {
     OM_uint32 major;
@@ -174,7 +177,8 @@ gssEapVerifyToken(OM_uint32 *minor,
     }
 
     major = verifyTokenHeader(minor, oid, &bodySize, &p,
-                              inputToken->length, tokenType);
+                              inputToken->length, tokenType,
+                              actualToken);
     if (GSS_ERROR(major))
         return GSS_S_DEFECTIVE_TOKEN;
 
index d6d8f51..df31460 100644 (file)
@@ -83,6 +83,8 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
 
     if (cred->krbCredCache != NULL)
         krb5_cc_destroy(krbContext, cred->krbCredCache);
+    if (cred->krbCred != GSS_C_NO_CREDENTIAL)
+        gssReleaseCred(&tmpMinor, &cred->krbCred);
 
     GSSEAP_MUTEX_DESTROY(&cred->mutex);
     memset(cred, 0, sizeof(*cred));
index 4063321..c442038 100644 (file)
 
 #include "gssapiP_eap.h"
 
+#include <dlfcn.h>
+
 /*
  * Fast reauthentication support for EAP GSS.
  */
 
 #define KRB5_AUTHDATA_RADIUS_AVP        513
 
+krb5_error_code
+krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
+
+krb5_error_code
+encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
+
 static krb5_error_code
 getAcceptorKey(krb5_context krbContext,
                gss_ctx_id_t ctx,
@@ -71,27 +79,22 @@ getAcceptorKey(krb5_context krbContext,
 
         while ((code = krb5_kt_next_entry(krbContext, keytab,
                                           &ktent, &cursor)) == 0) {
-            if (ktent.key.enctype != ctx->encryptionType) {
+            if (ktent.key.enctype == ctx->encryptionType) {
+                break;
+            } else {
                 krb5_free_keytab_entry_contents(krbContext, &ktent);
-                continue;
             }
         }
     }
 
-    code = krb5_copy_principal(krbContext, ktent.principal, princ);
-    if (code != 0)
-        goto cleanup;
-
-    code = krb5_copy_keyblock_contents(krbContext, &ktent.key, key);
-    if (code != 0)
-        goto cleanup;
+    if (code == 0) {
+        *princ = ktent.principal;
+        *key = ktent.key;
+    }
 
 cleanup:
     if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
         krb5_kt_end_seq_get(krbContext, keytab, &cursor);
-
-    krb5_free_keytab_entry_contents(krbContext, &ktent);
-    krb5_kt_end_seq_get(krbContext, keytab, &cursor);
     krb5_kt_close(krbContext, keytab);
 
     if (code != 0) {
@@ -106,11 +109,11 @@ cleanup:
     return code; 
 }
 
-static OM_uint32
-makeReauthCreds(OM_uint32 *minor,
-                gss_ctx_id_t ctx,
-                gss_cred_id_t cred,
-                gss_buffer_t credBuf)
+OM_uint32
+gssEapMakeReauthCreds(OM_uint32 *minor,
+                      gss_ctx_id_t ctx,
+                      gss_cred_id_t cred,
+                      gss_buffer_t credBuf)
 {
     OM_uint32 major = GSS_S_COMPLETE, code;
     krb5_context krbContext = NULL;
@@ -167,6 +170,10 @@ makeReauthCreds(OM_uint32 *minor,
     if (code != 0)
         goto cleanup;
 
+    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
+    if (code != 0)
+        goto cleanup;
+
     creds.client = enc_part.client;
     creds.server = ticket.server;
     creds.keyblock = session;
@@ -179,6 +186,10 @@ makeReauthCreds(OM_uint32 *minor,
     if (code != 0)
         goto cleanup;
 
+    code = krb5_auth_con_setflags(krbContext, authContext, 0);
+    if (code != 0)
+        goto cleanup;
+
     code = krb5_auth_con_setsendsubkey(krbContext, authContext, &ctx->rfc3961Key);
     if (code != 0)
         goto cleanup;
@@ -189,10 +200,6 @@ makeReauthCreds(OM_uint32 *minor,
 
     krbDataToGssBuffer(credsData, credBuf);
 
-    code = krb5_encrypt_tkt_part(krbContext, acceptorKey, &ticket);
-    if (code != 0)
-        goto cleanup;
-
 cleanup:
     *minor = code;
 
@@ -213,11 +220,11 @@ cleanup:
     return major;
 }
 
-static OM_uint32
-storeReauthCreds(OM_uint32 *minor,
-                 gss_ctx_id_t ctx,
-                 gss_cred_id_t cred,
-                 gss_buffer_t credBuf)
+OM_uint32
+gssEapStoreReauthCreds(OM_uint32 *minor,
+                       gss_ctx_id_t ctx,
+                       gss_cred_id_t cred,
+                       gss_buffer_t credBuf)
 {
     OM_uint32 major = GSS_S_COMPLETE, code;
     krb5_context krbContext = NULL;
@@ -235,6 +242,10 @@ storeReauthCreds(OM_uint32 *minor,
     if (code != 0)
         goto cleanup;
 
+    code = krb5_auth_con_setflags(krbContext, authContext, 0);
+    if (code != 0)
+        goto cleanup;
+
     code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
                                        &ctx->rfc3961Key);
     if (code != 0)
@@ -246,19 +257,20 @@ storeReauthCreds(OM_uint32 *minor,
     if (code != 0)
         goto cleanup;
 
+    if (creds == NULL || creds[0] == NULL)
+        goto cleanup;
 
+    code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
+    if (code != 0)
+        goto cleanup;
 
-/*
-OM_uint32 KRB5_CALLCONV
-gss_krb5_import_cred(OM_uint32 *minor_status,
-                     krb5_ccache id,
-                     krb5_principal keytab_principal,
-                     krb5_keytab keytab,
-                     gss_cred_id_t *cred);
-*/
+    code = krb5_cc_store_cred(krbContext, cred->krbCredCache, creds[0]);
+    if (code != 0)
+        goto cleanup;
 
-    if (creds != NULL && creds[0] != NULL) {
-    }    
+    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL, &cred->krbCred);
+    if (GSS_ERROR(major))
+        goto cleanup;
 
 cleanup:
     *minor = code;
@@ -273,3 +285,172 @@ cleanup:
 
     return major;
 }
+
+static OM_uint32 (*gssInitSecContextNext)(
+    OM_uint32 *minor,
+    gss_cred_id_t cred,
+    gss_ctx_id_t *context_handle,
+    gss_name_t target_name,
+    gss_OID mech_type,
+    OM_uint32 req_flags,
+    OM_uint32 time_req,
+    gss_channel_bindings_t input_chan_bindings,
+    gss_buffer_t input_token,
+    gss_OID *actual_mech_type,
+    gss_buffer_t output_token,
+    OM_uint32 *ret_flags,
+    OM_uint32 *time_rec);
+
+static OM_uint32 (*gssAcceptSecContextNext)(
+    OM_uint32 *minor,
+    gss_ctx_id_t *context_handle,
+    gss_cred_id_t cred,
+    gss_buffer_t input_token,
+    gss_channel_bindings_t input_chan_bindings,
+    gss_name_t *src_name,
+    gss_OID *mech_type,
+    gss_buffer_t output_token,
+    OM_uint32 *ret_flags,
+    OM_uint32 *time_rec,
+    gss_cred_id_t *delegated_cred_handle);
+
+static OM_uint32 (*gssReleaseCredNext)(
+    OM_uint32 *minor,
+    gss_cred_id_t *cred_handle);
+
+static OM_uint32 (*gssReleaseNameNext)(
+    OM_uint32 *minor,
+    gss_name_t *name);
+
+static OM_uint32 (*gssInquireSecContextByOidNext)(
+    OM_uint32 *minor,
+    const gss_ctx_id_t context_handle,
+    const gss_OID desired_object,
+    gss_buffer_set_t *data_set);
+
+static OM_uint32 (*gssDeleteSecContextNext)(
+    OM_uint32 *minor,
+    gss_ctx_id_t *context_handle,
+    gss_buffer_t output_token);
+
+static OM_uint32 (*gssDisplayNameNext)(
+    OM_uint32 *minor,
+    gss_name_t name,
+    gss_buffer_t output_name_buffer,
+    gss_OID *output_name_type);
+
+OM_uint32
+gssEapReauthInitialize(OM_uint32 *minor)
+{
+    gssInitSecContextNext = dlsym(RTLD_NEXT, "gss_init_sec_context");
+    gssAcceptSecContextNext = dlsym(RTLD_NEXT, "gss_accept_sec_context");
+    gssReleaseCredNext = dlsym(RTLD_NEXT, "gss_release_cred");
+    gssReleaseNameNext = dlsym(RTLD_NEXT, "gss_release_name");
+    gssInquireSecContextByOidNext = dlsym(RTLD_NEXT, "gss_inquire_sec_context_by_oid");
+    gssDeleteSecContextNext = dlsym(RTLD_NEXT, "gss_delete_sec_context");
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssInitSecContext(OM_uint32 *minor,
+                  gss_cred_id_t cred,
+                  gss_ctx_id_t *context_handle,
+                  gss_name_t target_name,
+                  gss_OID mech_type,
+                  OM_uint32 req_flags,
+                  OM_uint32 time_req,
+                  gss_channel_bindings_t input_chan_bindings,
+                  gss_buffer_t input_token,
+                  gss_OID *actual_mech_type,
+                  gss_buffer_t output_token,
+                  OM_uint32 *ret_flags,
+                  OM_uint32 *time_rec)
+{
+    if (gssInitSecContextNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssInitSecContextNext(minor, cred, context_handle,
+                                 target_name, mech_type, req_flags,
+                                 time_req, input_chan_bindings,
+                                 input_token, actual_mech_type,
+                                 output_token, ret_flags, time_rec);
+}
+
+OM_uint32
+gssAcceptSecContext(OM_uint32 *minor,
+                    gss_ctx_id_t *context_handle,
+                    gss_cred_id_t cred,
+                    gss_buffer_t input_token,
+                    gss_channel_bindings_t input_chan_bindings,
+                    gss_name_t *src_name,
+                    gss_OID *mech_type,
+                    gss_buffer_t output_token,
+                    OM_uint32 *ret_flags,
+                    OM_uint32 *time_rec,
+                    gss_cred_id_t *delegated_cred_handle)
+{
+    if (gssAcceptSecContextNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssAcceptSecContextNext(minor, context_handle, cred,
+                                   input_token, input_chan_bindings,
+                                   src_name, mech_type, output_token,
+                                   ret_flags, time_rec, delegated_cred_handle);
+}
+
+OM_uint32
+gssReleaseCred(OM_uint32 *minor,
+               gss_cred_id_t *cred_handle)
+{
+    if (gssReleaseCredNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssReleaseCredNext(minor, cred_handle);
+}
+
+OM_uint32
+gssReleaseName(OM_uint32 *minor,
+               gss_name_t *name)
+{
+    if (gssReleaseName == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssReleaseNameNext(minor, name);
+}
+
+OM_uint32
+gssDeleteSecContext(OM_uint32 *minor,
+                    gss_ctx_id_t *context_handle,
+                    gss_buffer_t output_token)
+{
+    if (gssDeleteSecContextNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssDeleteSecContextNext(minor, context_handle, output_token);
+}
+
+OM_uint32
+gssDisplayName(OM_uint32 *minor,
+               gss_name_t name,
+               gss_buffer_t buffer,
+               gss_OID *name_type)
+{
+    if (gssDisplayNameNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssDisplayNameNext(minor, name, buffer, name_type);
+}
+
+OM_uint32
+gssInquireSecContextByOid(OM_uint32 *minor,
+                          const gss_ctx_id_t context_handle,
+                          const gss_OID desired_object,
+                          gss_buffer_set_t *data_set)
+{
+    if (gssInquireSecContextByOidNext == NULL)
+        return GSS_S_UNAVAILABLE;
+
+    return gssInquireSecContextByOidNext(minor, context_handle,
+                                         desired_object, data_set);
+}
diff --git a/mech_eap/util_reauth.h b/mech_eap/util_reauth.h
new file mode 100644 (file)
index 0000000..55518dd
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010, 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"
+
+#ifndef _UTIL_REAUTH_H_
+#define _UTIL_REAUTH_H_ 1
+
+OM_uint32
+gssInitSecContext(OM_uint32 *minor,
+                  gss_cred_id_t cred,
+                  gss_ctx_id_t *context_handle,
+                  gss_name_t target_name,
+                  gss_OID mech_type,
+                  OM_uint32 req_flags,
+                  OM_uint32 time_req,
+                  gss_channel_bindings_t input_chan_bindings,
+                  gss_buffer_t input_token,
+                  gss_OID *actual_mech_type,
+                  gss_buffer_t output_token,
+                  OM_uint32 *ret_flags,
+                  OM_uint32 *time_rec);
+
+OM_uint32
+gssAcceptSecContext(OM_uint32 *minor,
+                    gss_ctx_id_t *context_handle,
+                    gss_cred_id_t cred,
+                    gss_buffer_t input_token,
+                    gss_channel_bindings_t input_chan_bindings,
+                    gss_name_t *src_name,
+                    gss_OID *mech_type,
+                    gss_buffer_t output_token,
+                    OM_uint32 *ret_flags,
+                    OM_uint32 *time_rec,
+                    gss_cred_id_t *delegated_cred_handle);
+
+OM_uint32
+gssReleaseCred(OM_uint32 *minor,
+               gss_cred_id_t *cred_handle);
+
+OM_uint32
+gssReleaseName(OM_uint32 *minor,
+               gss_name_t *name);
+
+OM_uint32
+gssDeleteSecContext(OM_uint32 *minor,
+                    gss_ctx_id_t *context_handle,
+                    gss_buffer_t output_token);
+
+OM_uint32
+gssDisplayName(OM_uint32 *minor,
+               gss_name_t name,
+               gss_buffer_t buffer,
+               gss_OID *name_type);
+
+OM_uint32
+gssInquireSecContextByOid(OM_uint32 *minor,
+                          const gss_ctx_id_t context_handle,
+                          const gss_OID desired_object,
+                          gss_buffer_set_t *data_set);
+
+OM_uint32
+gssEapMakeReauthCreds(OM_uint32 *minor,
+                      gss_ctx_id_t ctx,
+                      gss_cred_id_t cred,
+                      gss_buffer_t credBuf);
+
+OM_uint32
+gssEapStoreReauthCreds(OM_uint32 *minor,
+                       gss_ctx_id_t ctx,
+                       gss_cred_id_t cred,
+                       gss_buffer_t credBuf);
+
+#endif /* _UTIL_REAUTH_H_ */
index 7f3d3c2..7ddc582 100644 (file)
@@ -202,7 +202,8 @@ verifyTokenHeader(OM_uint32 *minor,
                   size_t *body_size,
                   unsigned char **buf_in,
                   size_t toksize_in,
-                  enum gss_eap_token_type tok_type)
+                  enum gss_eap_token_type tok_type,
+                  enum gss_eap_token_type *ret_tok_type)
 {
     unsigned char *buf = *buf_in;
     ssize_t seqsize;
@@ -253,9 +254,10 @@ verifyTokenHeader(OM_uint32 *minor,
         if ((toksize -= 2) < 0)
             return GSS_S_DEFECTIVE_TOKEN;
 
-        if ((*buf++ != ((tok_type >> 8) & 0xff)) ||
-            (*buf++ != (tok_type & 0xff)))
+        *ret_tok_type = load_uint16_be(*buf);
+        if (tok_type != *ret_tok_type)
             return GSS_S_DEFECTIVE_TOKEN;
+        *buf += 2;
     }
     *buf_in = buf;
     *body_size = toksize;