get reauthenticating working
authorLuke Howard <lukeh@padl.com>
Thu, 23 Sep 2010 08:53:16 +0000 (10:53 +0200)
committerLuke Howard <lukeh@padl.com>
Thu, 23 Sep 2010 08:53:16 +0000 (10:53 +0200)
mech_eap/accept_sec_context.c
mech_eap/gssapiP_eap.h
mech_eap/init_sec_context.c
mech_eap/unwrap_iov.c
mech_eap/util.h
mech_eap/util_context.c
mech_eap/util_reauth.c
mech_eap/util_token.c
mech_eap/wrap_iov.c

index 83f6f00..f223cc5 100644 (file)
@@ -472,7 +472,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
     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;
+    OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
 
     ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
 
@@ -487,7 +487,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
                                 &krbInitiator,
                                 &mech,
                                 outputToken,
-                                &ctx->gssFlags,
+                                &gssFlags,
                                 &timeRec,
                                 NULL);
     if (major == GSS_S_COMPLETE) {
@@ -495,6 +495,8 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
                                krbInitiator, mech, timeRec);
     }
 
+    ctx->gssFlags = gssFlags & ~(GSS_C_DCE_STYLE);
+
     gssReleaseName(&tmpMinor, &krbInitiator);
 
     return major;
@@ -538,6 +540,7 @@ gss_accept_sec_context(OM_uint32 *minor,
     gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
     enum gss_eap_token_type tokType;
+    int initialContextToken = 0;
 
     *minor = 0;
 
@@ -557,6 +560,7 @@ gss_accept_sec_context(OM_uint32 *minor,
         if (GSS_ERROR(major))
             return major;
 
+        initialContextToken = 1;
         *context_handle = ctx;
     }
 
@@ -565,16 +569,20 @@ gss_accept_sec_context(OM_uint32 *minor,
     sm = &eapGssAcceptorSm[ctx->state];
 
     major = gssEapVerifyToken(minor, ctx, input_token,
-                              sm->inputTokenType, &tokType,
-                              &innerInputToken);
-    if (major == GSS_S_DEFECTIVE_TOKEN && tokType == TOK_TYPE_GSS_REAUTH) {
+                              &tokType, &innerInputToken);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
         ctx->state = EAP_STATE_KRB_REAUTH_GSS;
-    } else if (GSS_ERROR(major)) {
+    } else if (tokType != sm->inputTokenType) {
+        major = GSS_S_DEFECTIVE_TOKEN;
         goto cleanup;
     }
 
     /* If credentials were provided, check they're usable with this mech */
-    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+    if (cred != GSS_C_NO_CREDENTIAL &&
+        !gssEapCredAvailable(cred, ctx->mechanismUsed)) {
         major = GSS_S_BAD_MECH;
         goto cleanup;
     }
@@ -632,4 +640,3 @@ cleanup:
 
     return major;
 }
-
index 0d7809b..c9c785c 100644 (file)
@@ -202,4 +202,7 @@ gssEapWrapIovLength(OM_uint32 *minor,
                     gss_iov_buffer_desc *iov,
                     int iov_count);
 
+unsigned char
+rfc4121Flags(gss_ctx_id_t ctx, int receiving);
+
 #endif /* _GSSAPIP_EAP_H_ */
index 4dd545c..0709b1f 100644 (file)
@@ -287,35 +287,31 @@ initReady(OM_uint32 *minor, gss_ctx_id_t ctx)
 }
 
 static OM_uint32
-eapGssSmInitIdentity(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)
+initBegin(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)
 {
-    time_t now;
     OM_uint32 major;
-    int initialContextToken;
 
-    initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
-                           inputToken->length == 0);
-    if (!initialContextToken)
-        return GSS_S_DEFECTIVE_TOKEN;
-
-    time(&now);
-    if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
+    if (cred != GSS_C_NO_CREDENTIAL && cred->expiryTime)
+        ctx->expiryTime = cred->expiryTime;
+    else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
         ctx->expiryTime = 0;
     else
-        ctx->expiryTime = now + timeReq;
+        ctx->expiryTime = time(NULL) + timeReq;
 
-    major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
-    if (GSS_ERROR(major))
-        return major;
+    if (cred != GSS_C_NO_CREDENTIAL) {
+        major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
+        if (GSS_ERROR(major))
+            return major;
+    }
 
     major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
     if (GSS_ERROR(major))
@@ -336,6 +332,34 @@ eapGssSmInitIdentity(OM_uint32 *minor,
     if (!gssEapCredAvailable(cred, ctx->mechanismUsed))
         return GSS_S_BAD_MECH;
 
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmInitIdentity(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)
+{
+    OM_uint32 major;
+    int initialContextToken;
+
+    initialContextToken = (inputToken->length == 0);
+    if (!initialContextToken)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    major = initBegin(minor, cred, ctx, target, mech,
+                      reqFlags, timeReq, chanBindings,
+                      inputToken, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
     ctx->state = EAP_STATE_AUTHENTICATE;
 
     return GSS_S_CONTINUE_NEEDED;
@@ -538,33 +562,6 @@ canReauthP(gss_cred_id_t cred)
 }
 
 static OM_uint32
-initReadyKrb(OM_uint32 *minor,
-            gss_ctx_id_t ctx,
-            gss_cred_id_t cred,
-            const gss_name_t target,
-            const gss_OID mech,
-            OM_uint32 timeRec)
-{
-    OM_uint32 major;
-
-    major = gssEapGlueToMechName(minor, target, &ctx->acceptorName);
-    if (GSS_ERROR(major))
-        return major;
-
-    major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
-    if (GSS_ERROR(major))
-        return major;
-
-    major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
-    if (GSS_ERROR(major))
-        return major;
-
-    ctx->state = EAP_STATE_ESTABLISHED;
-
-    return GSS_S_COMPLETE;
-}
-
-static OM_uint32
 eapGssSmInitGssReauth(OM_uint32 *minor,
                       gss_cred_id_t cred,
                       gss_ctx_id_t ctx,
@@ -579,12 +576,20 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
     OM_uint32 major, tmpMinor;
     gss_name_t mechTarget = GSS_C_NO_NAME;
     gss_OID actualMech = GSS_C_NO_OID;
-    OM_uint32 timeRec;
+    OM_uint32 gssFlags, timeRec;
 
     assert(cred != GSS_C_NO_CREDENTIAL);
 
     ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
 
+    if (inputToken->length == 0) {
+        major = initBegin(minor, cred, ctx, target, mech,
+                          reqFlags, timeReq, chanBindings,
+                          inputToken, outputToken);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+
     major = gssEapMechToGlueName(minor, target, &mechTarget);
     if (GSS_ERROR(major))
         goto cleanup;
@@ -594,17 +599,27 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
                               &ctx->kerberosCtx,
                               mechTarget,
                               (gss_OID)gss_mech_krb5,
-                              reqFlags,
+                              reqFlags | GSS_C_DCE_STYLE,
                               timeReq,
                               chanBindings,
                               inputToken,
                               &actualMech,
                               outputToken,
-                              &ctx->gssFlags,
+                              &gssFlags,
                               &timeRec);
     if (GSS_ERROR(major))
         goto cleanup;
 
+    ctx->gssFlags = gssFlags;
+
+    if (major == GSS_S_COMPLETE) {
+        major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        ctx->state = EAP_STATE_ESTABLISHED;
+    }
+
 cleanup:
     gssReleaseName(&tmpMinor, &mechTarget);
 
@@ -688,10 +703,14 @@ gss_init_sec_context(OM_uint32 *minor,
 
     if (input_token != GSS_C_NO_BUFFER) {
         major = gssEapVerifyToken(minor, ctx, input_token,
-                                  sm->inputTokenType,
                                   &tokType, &innerInputToken);
         if (GSS_ERROR(major))
             goto cleanup;
+
+        if (tokType != sm->inputTokenType) {
+            major = GSS_S_DEFECTIVE_TOKEN;
+            goto cleanup;
+        }
     } else {
         innerInputToken.length = 0;
         innerInputToken.value = NULL;
index 1624308..b178da8 100644 (file)
@@ -73,7 +73,7 @@ unwrapToken(OM_uint32 *minor,
     gss_iov_buffer_t header;
     gss_iov_buffer_t padding;
     gss_iov_buffer_t trailer;
-    unsigned char acceptorFlag;
+    unsigned char flags;
     unsigned char *ptr = NULL;
     int keyUsage;
     size_t rrc, ec;
@@ -99,7 +99,8 @@ unwrapToken(OM_uint32 *minor,
 
     trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
 
-    acceptorFlag = CTX_IS_INITIATOR(ctx) ? TOK_FLAG_SENDER_IS_ACCEPTOR : 0;
+    flags = rfc4121Flags(ctx, TRUE);
+
     switch (toktype) {
     case TOK_TYPE_WRAP:
         keyUsage = !CTX_IS_INITIATOR(ctx)
@@ -121,18 +122,11 @@ unwrapToken(OM_uint32 *minor,
 
     ptr = (unsigned char *)header->buffer.value;
 
-    if (header->buffer.length < 16) {
-        *minor = 0;
+    if (header->buffer.length < 16)
         return GSS_S_DEFECTIVE_TOKEN;
-    }
-
-    if ((ptr[2] & TOK_FLAG_SENDER_IS_ACCEPTOR) != acceptorFlag) {
-        return GSS_S_BAD_SIG;
-    }
 
-    if (ptr[2] & TOK_FLAG_ACCEPTOR_SUBKEY) {
+    if ((ptr[2] & flags) != flags)
         return GSS_S_BAD_SIG;
-    }
 
     if (toktype == TOK_TYPE_WRAP) {
         unsigned int krbTrailerLen;
index bc80e08..6b647e3 100644 (file)
@@ -171,8 +171,7 @@ OM_uint32
 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,
+                  enum gss_eap_token_type *tokenType,
                   gss_buffer_t innerInputToken);
 
 OM_uint32
@@ -399,7 +398,6 @@ 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 *ret_tok_type);
 
 /* Helper macros */
index 146b9a9..972afa6 100644 (file)
@@ -158,7 +158,6 @@ OM_uint32
 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)
 {
@@ -177,10 +176,9 @@ gssEapVerifyToken(OM_uint32 *minor,
     }
 
     major = verifyTokenHeader(minor, oid, &bodySize, &p,
-                              inputToken->length, tokenType,
-                              actualToken);
+                              inputToken->length, actualToken);
     if (GSS_ERROR(major))
-        return GSS_S_DEFECTIVE_TOKEN;
+        return major;
 
     if (ctx->mechanismUsed == GSS_C_NO_OID) {
         if (!gssEapIsConcreteMechanismOid(oid))
index bc7626a..a63ca06 100644 (file)
@@ -174,11 +174,11 @@ gssEapMakeReauthCreds(OM_uint32 *minor,
 
     ticket.enc_part2 = &enc_part;
 
-    code = encode_krb5_ticket(&ticket, &ticketData);
+    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
     if (code != 0)
         goto cleanup;
 
-    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
+    code = encode_krb5_ticket(&ticket, &ticketData);
     if (code != 0)
         goto cleanup;
 
@@ -227,6 +227,18 @@ cleanup:
     return major;
 }
 
+static int
+isTicketGrantingServiceP(krb5_context krbContext,
+                         krb5_const_principal principal)
+{
+    if (krb5_princ_size(krbContext, principal) == 2 &&
+        krb5_princ_component(krbContext, principal, 0)->length == 6 &&
+        memcmp(krb5_princ_component(krbContext, principal, 0)->data, "krbtgt", 6) == 0)
+        return TRUE;
+
+    return FALSE;
+}
+
 OM_uint32
 gssEapStoreReauthCreds(OM_uint32 *minor,
                        gss_ctx_id_t ctx,
@@ -269,6 +281,7 @@ gssEapStoreReauthCreds(OM_uint32 *minor,
         goto cleanup;
 
     code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
+    if (code != 0)
         goto cleanup;
 
     krb5_free_principal(krbContext, cred->name->krbPrincipal);
@@ -284,11 +297,20 @@ gssEapStoreReauthCreds(OM_uint32 *minor,
     if (code != 0)
         goto cleanup;
 
-    code = krb5_cc_store_cred(krbContext, cred->krbCredCache, creds[0]);
-    if (code != 0)
-        goto cleanup;
+    for (i = 0; creds[i] != NULL; i++) {
+        krb5_creds kcred = *(creds[i]);
+
+        /* Swap in the acceptor name the client asked for so get_credentials() works */
+        if (!isTicketGrantingServiceP(krbContext, kcred.server))
+            kcred.server = ctx->acceptorName->krbPrincipal;
+
+        code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
+        if (code != 0)
+            goto cleanup;
+    }
 
-    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL, &cred->krbCred);
+    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
+                                 &cred->krbCred);
     if (GSS_ERROR(major))
         goto cleanup;
 
@@ -511,7 +533,7 @@ gssKrbExtractAuthzDataFromSecContext(OM_uint32 *minor,
     if (gssKrbExtractAuthzDataFromSecContextNext == NULL)
         return GSS_S_UNAVAILABLE;
 
-    return gssKrbExtractAuthzDataFromSecContext(minor, ctx, ad_type, ad_data);
+    return gssKrbExtractAuthzDataFromSecContextNext(minor, ctx, ad_type, ad_data);
 }
 
 OM_uint32
@@ -635,7 +657,6 @@ gssEapReauthComplete(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
-    ctx->mechanismUsed = GSS_EAP_MECHANISM;
     major = GSS_S_COMPLETE;
 
 cleanup:
@@ -643,4 +664,3 @@ cleanup:
 
     return major;
 }
-
index b985215..02d6557 100644 (file)
@@ -202,7 +202,6 @@ 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 *ret_tok_type)
 {
     unsigned char *buf = *buf_in;
@@ -212,6 +211,9 @@ verifyTokenHeader(OM_uint32 *minor,
 
     *minor = 0;
 
+    if (ret_tok_type != NULL)
+        *ret_tok_type = TOK_TYPE_NONE;
+
     if ((toksize -= 1) < 0)
         return GSS_S_DEFECTIVE_TOKEN;
 
@@ -250,13 +252,11 @@ verifyTokenHeader(OM_uint32 *minor,
         return GSS_S_BAD_MECH;
     }
 
-    if (tok_type != TOK_TYPE_NONE) {
+    if (ret_tok_type != NULL) {
         if ((toksize -= 2) < 0)
             return GSS_S_DEFECTIVE_TOKEN;
 
         *ret_tok_type = load_uint16_be(buf);
-        if (tok_type != *ret_tok_type)
-            return GSS_S_DEFECTIVE_TOKEN;
         buf += 2;
     }
     *buf_in = buf;
index 9a10fe3..994dded 100644 (file)
 
 #include "gssapiP_eap.h"
 
+unsigned char
+rfc4121Flags(gss_ctx_id_t ctx, int receiving)
+{
+    unsigned char flags;
+    int isAcceptor;
+
+    isAcceptor = !CTX_IS_INITIATOR(ctx);
+    if (receiving)
+        isAcceptor = !isAcceptor;
+
+    flags = 0;
+    if (isAcceptor)
+        flags |= TOK_FLAG_SENDER_IS_ACCEPTOR;
+
+    if ((ctx->flags & CTX_FLAG_KRB_REAUTH_GSS) &&
+        (ctx->gssFlags & GSS_C_MUTUAL_FLAG))
+        flags |= TOK_FLAG_ACCEPTOR_SUBKEY;
+
+    return flags;
+}
+
 OM_uint32
 gssEapWrapOrGetMIC(OM_uint32 *minor,
                    gss_ctx_id_t ctx,
@@ -68,7 +89,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
     gss_iov_buffer_t header;
     gss_iov_buffer_t padding;
     gss_iov_buffer_t trailer;
-    unsigned char acceptorFlag;
+    unsigned char flags;
     unsigned char *outbuf = NULL;
     unsigned char *tbuf = NULL;
     int keyUsage;
@@ -82,7 +103,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
 
     GSSEAP_KRB_INIT(&krbContext);
 
-    acceptorFlag = CTX_IS_INITIATOR(ctx) ? 0 : TOK_FLAG_SENDER_IS_ACCEPTOR;
+    flags = rfc4121Flags(ctx, FALSE);
 
     switch (toktype) {
     case TOK_TYPE_WRAP:
@@ -177,9 +198,8 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
         /* TOK_ID */
         store_uint16_be((uint16_t)toktype, outbuf);
         /* flags */
-        outbuf[2] = (acceptorFlag
-                     | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0)
-                     | (0 ? TOK_FLAG_ACCEPTOR_SUBKEY : 0));
+        outbuf[2] = flags
+                     | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0);
         /* filler */
         outbuf[3] = 0xFF;
         /* EC */
@@ -251,8 +271,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
         /* TOK_ID */
         store_uint16_be((uint16_t)toktype, outbuf);
         /* flags */
-        outbuf[2] = (acceptorFlag
-                     | (0 ? TOK_FLAG_ACCEPTOR_SUBKEY : 0));
+        outbuf[2] = flags;
         /* filler */
         outbuf[3] = 0xFF;
         if (toktype == TOK_TYPE_WRAP) {