Implement channel bindings
authorLuke Howard <lukeh@padl.com>
Fri, 10 Sep 2010 11:08:23 +0000 (13:08 +0200)
committerLuke Howard <lukeh@padl.com>
Fri, 10 Sep 2010 11:08:23 +0000 (13:08 +0200)
mech_eap/accept_sec_context.c
mech_eap/get_mic.c
mech_eap/gssapiP_eap.h
mech_eap/init_sec_context.c
mech_eap/unwrap_iov.c
mech_eap/util.h
mech_eap/util_cksum.c
mech_eap/util_context.c
mech_eap/util_cred.c
mech_eap/util_token.c
mech_eap/wrap_iov.c

index 3c1e98f..4efda99 100644 (file)
@@ -216,7 +216,7 @@ serverGetEapReqIdText(void *ctx,
 #endif
 
 static OM_uint32
-completeAccept(OM_uint32 *minor, gss_ctx_id_t ctx)
+acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx)
 {
     OM_uint32 major;
     krb5_context krbContext;
@@ -310,8 +310,12 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
 
     if (ctx->acceptorCtx.eapPolInterface->eapSuccess) {
         ctx->acceptorCtx.eapPolInterface->eapSuccess = 0;
-        ctx->state = EAP_STATE_ESTABLISHED;
-        major = completeAccept(minor, ctx);
+        major = acceptReady(minor, ctx);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
+        major = GSS_S_CONTINUE_NEEDED;
     } else if (ctx->acceptorCtx.eapPolInterface->eapFail) {
         ctx->acceptorCtx.eapPolInterface->eapFail = 0;
         major = GSS_S_FAILURE;
@@ -340,6 +344,59 @@ cleanup:
 }
 
 static OM_uint32
+eapGssSmAcceptGssChannelBindings(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_iov_buffer_desc iov[2];
+
+    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;
+    }
+
+    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+    iov[0].buffer.length = 0;
+    iov[0].buffer.value = NULL;
+
+    major = gssEapEncodeGssChannelBindings(minor, chanBindings,
+                                            &iov[0].buffer);
+    if (GSS_ERROR(major))
+        return major;
+
+    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);
+
+    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;
+    }
+
+    gss_release_buffer(&tmpMinor, &iov[0].buffer);
+
+    return major;
+}
+
+static OM_uint32
 eapGssSmAcceptEstablished(OM_uint32 *minor,
                           gss_ctx_id_t ctx,
                           gss_cred_id_t cred,
@@ -362,11 +419,13 @@ static struct eap_gss_acceptor_sm {
                               gss_channel_bindings_t,
                               gss_buffer_t);
 } eapGssAcceptorSm[] = {
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptAuthenticate   },
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                         },
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                         },
-    { TOK_TYPE_GSS_CB,      TOK_TYPE_NONE,     NULL                         },
-    { TOK_TYPE_NONE,        TOK_TYPE_NONE,     eapGssSmAcceptEstablished    },
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptAuthenticate       },
+#if 0
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                             },
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                             },
+#endif
+    { TOK_TYPE_GSS_CB,      TOK_TYPE_NONE,     eapGssSmAcceptGssChannelBindings },
+    { TOK_TYPE_NONE,        TOK_TYPE_NONE,     eapGssSmAcceptEstablished        },
 };
 
 OM_uint32
@@ -421,7 +480,15 @@ gss_accept_sec_context(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
+    /* If credentials were provided, check they're usable with this mech */
+    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+        major = GSS_S_BAD_MECH;
+        goto cleanup;
+    }
+
     do {
+        sm = &eapGssAcceptorSm[ctx->state];
+
         major = (sm->processToken)(minor,
                                    ctx,
                                    cred,
index c91d63b..f623bc2 100644 (file)
@@ -45,6 +45,9 @@ gss_get_mic(OM_uint32 *minor,
     message_token->value = NULL;
     message_token->length = 0;
 
+    if (!CTX_IS_ESTABLISHED(ctx))
+        return GSS_S_NO_CONTEXT;
+
     iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
     iov[0].buffer = *message_buffer;
 
@@ -52,7 +55,7 @@ gss_get_mic(OM_uint32 *minor,
     iov[1].buffer.value = NULL;
     iov[1].buffer.length = 0;
 
-    major = gssEapWrapOrGetMIC(minor, ctx, FALSE, FALSE, iov, 2, TOK_TYPE_MIC);
+    major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
     if (major == GSS_S_COMPLETE) {
         *message_token = iov[1].buffer;
     }
index 4e34b78..5fb8383 100644 (file)
@@ -95,8 +95,10 @@ struct gss_cred_id_struct {
 
 enum eap_gss_state {
     EAP_STATE_AUTHENTICATE = 0,
+#if 0
     EAP_STATE_KEY_TRANSPORT,
     EAP_STATE_SECURE_ASSOCIATION,
+#endif
     EAP_STATE_GSS_CHANNEL_BINDINGS,
     EAP_STATE_ESTABLISHED
 };
@@ -156,6 +158,7 @@ struct gss_ctx_id_struct {
 #define KEY_USAGE_ACCEPTOR_SIGN             23
 #define KEY_USAGE_INITIATOR_SEAL            24
 #define KEY_USAGE_INITIATOR_SIGN            25
+#define KEY_USAGE_CHANNEL_BINDINGS          64
 
 /* wrap_iov.c */
 OM_uint32
index 83886a7..206590f 100644 (file)
@@ -233,8 +233,7 @@ peerConfigFree(OM_uint32 *minor,
 }
 
 static OM_uint32
-completeInit(OM_uint32 *minor,
-             gss_ctx_id_t ctx)
+initReady(OM_uint32 *minor, gss_ctx_id_t ctx)
 {
     OM_uint32 major;
     const unsigned char *key;
@@ -289,7 +288,10 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
     OM_uint32 tmpMajor, tmpMinor;
     time_t now;
     int initialContextToken = 0, code;
-    struct wpabuf *resp = NULL;
+    gss_buffer_desc respBuf;
+
+    respBuf.length = 0;
+    respBuf.value = NULL;
 
     initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
                            inputToken->length == 0);
@@ -334,9 +336,13 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
         if (GSS_ERROR(major))
             goto cleanup;
 
-        /* Use this to emit an empty token*/
-        wpabuf_set(&ctx->initiatorCtx.reqData, "", 0);
-        resp = &ctx->initiatorCtx.reqData;
+        /* If credentials were provided, check they're usable with this mech */
+        if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+            major = GSS_S_BAD_MECH;
+            goto cleanup;
+        }
+
+        respBuf.value = ""; /* emit empty inner token */
         major = GSS_S_CONTINUE_NEEDED;
         goto cleanup;
     } else {
@@ -350,28 +356,34 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
 
     code = eap_peer_sm_step(ctx->initiatorCtx.eap);
     if (ctx->flags & CTX_FLAG_EAP_RESP) {
+        struct wpabuf *resp;
+
         ctx->flags &= ~(CTX_FLAG_EAP_RESP);
 
         resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
+        if (resp != NULL) {
+            respBuf.length = wpabuf_len(resp);
+            respBuf.value = (void *)wpabuf_head(resp);
+        }
     } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
-        major = completeInit(minor, ctx);
+        major = initReady(minor, ctx);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
         ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
-        ctx->state = EAP_STATE_ESTABLISHED;
+        major = GSS_S_CONTINUE_NEEDED;
+        ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
     } else if ((ctx->flags & CTX_FLAG_EAP_FAIL) || code == 0) {
         major = GSS_S_FAILURE;
     }
 
 cleanup:
-    if (resp != NULL) {
+    if (respBuf.value != NULL) {
         OM_uint32 tmpMajor;
-        gss_buffer_desc buf;
 
         assert(major == GSS_S_CONTINUE_NEEDED);
 
-        buf.length = wpabuf_len(resp);
-        buf.value = (void *)wpabuf_head(resp);
-
-        tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken);
+        tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
         if (GSS_ERROR(tmpMajor)) {
             major = tmpMajor;
             *minor = tmpMinor;
@@ -384,6 +396,7 @@ cleanup:
     return major;
 }
 
+#if 0
 static OM_uint32
 eapGssSmInitKeyTransport(OM_uint32 *minor,
                          gss_cred_id_t cred,
@@ -413,6 +426,7 @@ eapGssSmInitSecureAssoc(OM_uint32 *minor,
 {
     GSSEAP_NOT_IMPLEMENTED;
 }
+#endif
 
 static OM_uint32
 eapGssSmInitGssChannelBindings(OM_uint32 *minor,
@@ -426,7 +440,53 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                gss_buffer_t inputToken,
                                gss_buffer_t outputToken)
 {
-    GSSEAP_NOT_IMPLEMENTED;
+    OM_uint32 major, tmpMinor;
+    gss_iov_buffer_desc iov[2];
+    gss_buffer_desc buf;
+
+    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+    iov[0].buffer.length = 0;
+    iov[0].buffer.value = NULL;
+
+    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+    iov[1].buffer.length = 0;
+    iov[1].buffer.value = NULL;
+
+    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
+        major = gssEapEncodeGssChannelBindings(minor, chanBindings,
+                                                &iov[0].buffer);
+        if (GSS_ERROR(major))
+            goto cleanup;
+
+        iov[0].type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
+    } else {
+        iov[0].buffer.length = sizeof("NO_CHANNEL_BINDINGS") - 1;
+        iov[0].buffer.value = "NO_CHANNEL_BINDINGS";
+    }
+
+    major = gssEapWrapOrGetMIC(minor, ctx, FALSE, FALSE, iov, 2,
+                               TOK_TYPE_GSS_CB);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    /* Skip past token ID */
+    assert(iov[1].buffer.length > 2);
+    assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB);
+
+    buf.length = iov[1].buffer.length - 2;
+    buf.value = (unsigned char *)iov[1].buffer.value + 2;
+
+    major = duplicateBuffer(minor, &buf, outputToken);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = GSS_S_COMPLETE;
+    ctx->state = EAP_STATE_ESTABLISHED;
+
+cleanup:
+    gssEapReleaseIov(iov, 2);
+
+    return major;
 }
 
 static OM_uint32
@@ -461,9 +521,11 @@ static struct eap_gss_initiator_sm {
                               gss_buffer_t);
 } eapGssInitiatorSm[] = {
     { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitAuthenticate        },
+#if 0
     { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitKeyTransport        },
     { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitSecureAssoc         },
-    { TOK_TYPE_GSS_CB,  TOK_TYPE_NONE,      eapGssSmInitGssChannelBindings  },
+#endif
+    { TOK_TYPE_NONE,    TOK_TYPE_GSS_CB,    eapGssSmInitGssChannelBindings  },
     { TOK_TYPE_NONE,    TOK_TYPE_NONE,      eapGssSmInitEstablished         },
 };
 
@@ -533,6 +595,8 @@ gss_init_sec_context(OM_uint32 *minor,
      * the status is not GSS_S_COMPLETE or an error status.
      */
     do {
+        sm = &eapGssInitiatorSm[ctx->state];
+
         major = (sm->processToken)(minor,
                                    cred,
                                    ctx,
index d10f71c..ae33843 100644 (file)
@@ -100,13 +100,22 @@ 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;
-    keyUsage = (toktype == TOK_TYPE_WRAP
-                ? (!CTX_IS_INITIATOR(ctx)
+    switch (toktype) {
+    case TOK_TYPE_WRAP:
+        keyUsage = !CTX_IS_INITIATOR(ctx)
                    ? KEY_USAGE_INITIATOR_SEAL
-                   : KEY_USAGE_ACCEPTOR_SEAL)
-                : (!CTX_IS_INITIATOR(ctx)
+                   : KEY_USAGE_ACCEPTOR_SEAL;
+        break;
+    case TOK_TYPE_GSS_CB:
+        keyUsage = KEY_USAGE_CHANNEL_BINDINGS;
+        break;
+    case TOK_TYPE_MIC:
+    default:
+        keyUsage = !CTX_IS_INITIATOR(ctx)
                    ? KEY_USAGE_INITIATOR_SIGN
-                   : KEY_USAGE_ACCEPTOR_SIGN));
+                   : KEY_USAGE_ACCEPTOR_SIGN;
+        break;
+    }
 
     gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
 
@@ -210,8 +219,8 @@ unwrapToken(OM_uint32 *minor,
         }
 
         code = sequenceCheck(&ctx->seqState, seqnum);
-    } else if (toktype == TOK_TYPE_MIC) {
-        if (load_uint16_be(ptr) != TOK_TYPE_MIC)
+    } else if (toktype == TOK_TYPE_MIC || toktype == TOK_TYPE_GSS_CB) {
+        if (load_uint16_be(ptr) != toktype)
             goto defective;
 
     verify_mic_1:
@@ -226,7 +235,8 @@ unwrapToken(OM_uint32 *minor,
             *minor = code;
             return GSS_S_BAD_SIG;
         }
-        code = sequenceCheck(&ctx->seqState, seqnum);
+        if (toktype != TOK_TYPE_GSS_CB)
+            code = sequenceCheck(&ctx->seqState, seqnum);
     } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
         if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
             goto defective;
index 42b2ed6..86fa6f7 100644 (file)
@@ -112,6 +112,11 @@ gssEapVerify(krb5_context context,
              int iov_count,
              int *valid);
 
+OM_uint32
+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
+                               gss_channel_bindings_t chanBindings,
+                               gss_buffer_t encodedBindings);
+
 /* util_context.c */
 OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
 OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
@@ -145,6 +150,8 @@ gssEapAcquireCred(OM_uint32 *minor,
                   gss_OID_set *pActualMechs,
                   OM_uint32 *timeRec);
 
+int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
+
 /* util_crypt.c */
 int
 gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
@@ -332,8 +339,9 @@ makeTokenHeader(const gss_OID_desc *mech,
                 unsigned char **buf,
                 enum gss_eap_token_type tok_type);
 
-int
-verifyTokenHeader(gss_OID mech,
+OM_uint32
+verifyTokenHeader(OM_uint32 *minor,
+                  gss_OID mech,
                   size_t *body_size,
                   unsigned char **buf_in,
                   size_t toksize_in,
@@ -432,4 +440,17 @@ load_uint64_be(const void *cvp)
     return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
 }
 
+static inline void
+store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
+{
+    unsigned char *p = (unsigned char *)vp;
+
+    if (wide_nums)
+        store_uint64_be(buffer->length, p);
+    else
+        store_uint32_be(buffer->length, p);
+    if (buffer->value != NULL)
+        memcpy(p + 4, buffer->value, buffer->length);
+}
+
 #endif /* _UTIL_H_ */
index d2b0bd8..505256c 100644 (file)
@@ -169,3 +169,46 @@ gssEapVerify(krb5_context context,
     return gssEapChecksum(context, type, rrc, key,
                           sign_usage, iov, iov_count, 1, valid);
 }
+
+OM_uint32
+gssEapEncodeGssChannelBindings(OM_uint32 *minor,
+                               gss_channel_bindings_t chanBindings,
+                               gss_buffer_t encodedBindings)
+{
+    OM_uint32 major, tmpMinor;
+    size_t length;
+    unsigned char *p;
+
+    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
+        length = sizeof(OM_uint32) * 5;
+        length += chanBindings->initiator_address.length;
+        length += chanBindings->acceptor_address.length;
+        length += chanBindings->application_data.length;
+
+        encodedBindings->value = GSSEAP_MALLOC(length);
+        if (encodedBindings->value == NULL) {
+            *minor = ENOMEM;
+            return GSS_S_FAILURE;
+        }
+
+        encodedBindings->length = length;
+        p = (unsigned char *)encodedBindings->value;
+
+        store_uint32_be(chanBindings->initiator_addrtype, p);
+        store_buffer(&chanBindings->initiator_address, p + 4, 0);
+        p += 4 + chanBindings->initiator_address.length;
+
+        store_uint32_be(chanBindings->acceptor_addrtype, p);
+        store_buffer(&chanBindings->acceptor_address, p + 4, 0);
+        p += 4 + chanBindings->acceptor_address.length;
+
+        store_buffer(&chanBindings->application_data, p, 1);
+        p += chanBindings->application_data.length;
+    } else {
+        encodedBindings->length = 0;
+        encodedBindings->value = NULL;
+    }
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
index eff975c..6ff5121 100644 (file)
@@ -167,9 +167,10 @@ gssEapVerifyToken(OM_uint32 *minor,
         oid = &oidBuf;
     }
 
-    major = verifyTokenHeader(oid, &bodySize, &p, inputToken->length, tokenType);
+    major = verifyTokenHeader(minor, oid, &bodySize, &p,
+                              inputToken->length, tokenType);
     if (GSS_ERROR(major))
-        return major;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if (ctx->mechanismUsed == GSS_C_NO_OID) {
         if (!gssEapIsConcreteMechanismOid(oid))
index 1377f5e..d1f31ee 100644 (file)
@@ -131,7 +131,7 @@ gssEapAcquireCred(OM_uint32 *minor,
             buf.value = getlogin(); /* XXX */
             buf.length = strlen((char *)buf.value);
 
-            major = gss_import_name(&minor, &buf,
+            major = gss_import_name(minor, &buf,
                                     GSS_C_NT_USER_NAME, &cred->name);
             if (GSS_ERROR(major))
                 goto cleanup;
@@ -174,3 +174,19 @@ cleanup:
 
     return major;
 }
+
+int
+gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
+{
+    OM_uint32 minor;
+    int present = 0;
+
+    assert(mech != GSS_C_NO_OID);
+
+    if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
+        return TRUE;
+
+    gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
+
+    return present;
+}
index c331945..7f3d3c2 100644 (file)
@@ -196,8 +196,9 @@ makeTokenHeader(
  * *body_size are left unmodified on error.
  */
 
-int
-verifyTokenHeader(gss_OID mech,
+OM_uint32
+verifyTokenHeader(OM_uint32 *minor,
+                  gss_OID mech,
                   size_t *body_size,
                   unsigned char **buf_in,
                   size_t toksize_in,
@@ -208,32 +209,34 @@ verifyTokenHeader(gss_OID mech,
     gss_OID_desc toid;
     ssize_t toksize = (ssize_t)toksize_in;
 
+    *minor = 0;
+
     if ((toksize -= 1) < 0)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if (*buf++ != 0x60)
-        return EINVAL;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     seqsize = der_read_length(&buf, &toksize);
     if (seqsize < 0)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if (seqsize != toksize)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if ((toksize -= 1) < 0)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if (*buf++ != 0x06)
-        return EINVAL;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     if ((toksize -= 1) < 0)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     toid.length = *buf++;
 
     if ((toksize -= toid.length) < 0)
-        return ERANGE;
+        return GSS_S_DEFECTIVE_TOKEN;
 
     toid.elements = buf;
     buf += toid.length;
@@ -241,21 +244,21 @@ verifyTokenHeader(gss_OID mech,
     if (mech->elements == NULL) {
         *mech = toid;
         if (toid.length == 0)
-            return EINVAL;
+            return GSS_S_BAD_MECH;
     } else if (!oidEqual(&toid, mech)) {
-        return EINVAL;
+        return GSS_S_BAD_MECH;
     }
 
     if (tok_type != TOK_TYPE_NONE) {
         if ((toksize -= 2) < 0)
-            return EINVAL;
+            return GSS_S_DEFECTIVE_TOKEN;
 
         if ((*buf++ != ((tok_type >> 8) & 0xff)) ||
             (*buf++ != (tok_type & 0xff)))
-            return EINVAL;
+            return GSS_S_DEFECTIVE_TOKEN;
     }
     *buf_in = buf;
     *body_size = toksize;
 
-    return 0;
+    return GSS_S_COMPLETE;
 }
index 6f53365..ec360e6 100644 (file)
@@ -77,22 +77,29 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
     size_t dataLen, assocDataLen;
     krb5_context krbContext;
 
-    if (!CTX_IS_ESTABLISHED(ctx))
-        return GSS_S_NO_CONTEXT;
-
     if (ctx->encryptionType == ENCTYPE_NULL)
         return GSS_S_UNAVAILABLE;
 
     GSSEAP_KRB_INIT(&krbContext);
 
     acceptorFlag = CTX_IS_INITIATOR(ctx) ? 0 : TOK_FLAG_SENDER_IS_ACCEPTOR;
-    keyUsage = ((toktype == TOK_TYPE_WRAP)
-                ? (CTX_IS_INITIATOR(ctx)
+
+    switch (toktype) {
+    case TOK_TYPE_WRAP:
+        keyUsage = CTX_IS_INITIATOR(ctx)
                    ? KEY_USAGE_INITIATOR_SEAL
-                   : KEY_USAGE_ACCEPTOR_SEAL)
-                : (CTX_IS_INITIATOR(ctx)
+                   : KEY_USAGE_ACCEPTOR_SEAL;
+        break;
+    case TOK_TYPE_GSS_CB:
+        keyUsage = KEY_USAGE_CHANNEL_BINDINGS;
+        break;
+    case TOK_TYPE_MIC:
+    default:
+        keyUsage = CTX_IS_INITIATOR(ctx)
                    ? KEY_USAGE_INITIATOR_SIGN
-                   : KEY_USAGE_ACCEPTOR_SIGN));
+                   : KEY_USAGE_ACCEPTOR_SIGN;
+        break;
+    }
 
     gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
 
@@ -269,7 +276,8 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
         if (code != 0)
             goto cleanup;
 
-        ctx->sendSeq++;
+        if (toktype != TOK_TYPE_GSS_CB)
+            ctx->sendSeq++;
 
         if (toktype == TOK_TYPE_WRAP) {
             /* Fix up EC field */
@@ -277,7 +285,7 @@ gssEapWrapOrGetMIC(OM_uint32 *minor,
             /* Fix up RRC field */
             store_uint16_be(rrc, outbuf + 6);
         }
-    } else if (toktype == TOK_TYPE_MIC) {
+    } else if (toktype == TOK_TYPE_MIC || toktype == TOK_TYPE_GSS_CB) {
         trailer = NULL;
         goto wrap_with_checksum;
     } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
@@ -307,6 +315,9 @@ gss_wrap_iov(OM_uint32 *minor,
              gss_iov_buffer_desc *iov,
              int iov_count)
 {
+    if (!CTX_IS_ESTABLISHED(ctx))
+        return GSS_S_NO_CONTEXT;
+
     return gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
                              iov, iov_count, TOK_TYPE_WRAP);
 }