void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state) { GSSEAP_ASSERT(state >= GSSEAP_STATE_INITIAL); GSSEAP_ASSERT(state <= GSSEAP_STATE_ESTABLISHED); fprintf(stderr, "GSS-EAP: state transition %s->%s\n", gssEapStateToString(GSSEAP_SM_STATE(ctx)), gssEapStateToString(state)); ctx->state = state; }
OM_uint32 gssEapExportSecContext(OM_uint32 *minor, gss_ctx_id_t ctx, gss_buffer_t token) { OM_uint32 major, tmpMinor; size_t length; gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER; gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER; gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER; gss_buffer_desc key; unsigned char *p; if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) || ctx->mechanismUsed == GSS_C_NO_OID) { *minor = GSSEAP_CONTEXT_INCOMPLETE; return GSS_S_NO_CONTEXT; } key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key); key.value = KRB_KEY_DATA(&ctx->rfc3961Key); if (ctx->initiatorName != GSS_C_NO_NAME) { major = gssEapExportNameInternal(minor, ctx->initiatorName, &initiatorName, EXPORT_NAME_FLAG_COMPOSITE); if (GSS_ERROR(major)) goto cleanup; } if (ctx->acceptorName != GSS_C_NO_NAME) { major = gssEapExportNameInternal(minor, ctx->acceptorName, &acceptorName, EXPORT_NAME_FLAG_COMPOSITE); if (GSS_ERROR(major)) goto cleanup; } #ifdef GSSEAP_ENABLE_ACCEPTOR /* * The partial context is only transmitted for unestablished acceptor * contexts. */ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) && (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { major = gssEapExportPartialContext(minor, ctx, &partialCtx); if (GSS_ERROR(major)) goto cleanup; } #endif length = 16; /* version, state, flags, */ length += 4 + ctx->mechanismUsed->length; /* mechanismUsed */ length += 12 + key.length; /* rfc3961Key.value */ length += 4 + initiatorName.length; /* initiatorName.value */ length += 4 + acceptorName.length; /* acceptorName.value */ length += 24 + sequenceSize(ctx->seqState); /* seqState */ if (partialCtx.value != NULL) length += 4 + partialCtx.length; /* partialCtx.value */ token->value = GSSEAP_MALLOC(length); if (token->value == NULL) { major = GSS_S_FAILURE; *minor = ENOMEM; goto cleanup; } token->length = length; p = (unsigned char *)token->value; store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]); /* version */ store_uint32_be(GSSEAP_SM_STATE(ctx), &p[4]); store_uint32_be(ctx->flags, &p[8]); store_uint32_be(ctx->gssFlags, &p[12]); p = store_oid(ctx->mechanismUsed, &p[16]); store_uint32_be(ctx->checksumType, &p[0]); store_uint32_be(ctx->encryptionType, &p[4]); p = store_buffer(&key, &p[8], FALSE); p = store_buffer(&initiatorName, p, FALSE); p = store_buffer(&acceptorName, p, FALSE); store_uint64_be(ctx->expiryTime, &p[0]); store_uint64_be(ctx->sendSeq, &p[8]); store_uint64_be(ctx->recvSeq, &p[16]); p += 24; major = sequenceExternalize(minor, ctx->seqState, &p, &length); if (GSS_ERROR(major)) goto cleanup; if (partialCtx.value != NULL) p = store_buffer(&partialCtx, p, FALSE); GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length); major = GSS_S_COMPLETE; *minor = 0; cleanup: if (GSS_ERROR(major)) gss_release_buffer(&tmpMinor, token); gss_release_buffer(&tmpMinor, &initiatorName); gss_release_buffer(&tmpMinor, &acceptorName); gss_release_buffer(&tmpMinor, &partialCtx); return major; }
OM_uint32 gssEapImportContext(OM_uint32 *minor, gss_buffer_t token, gss_ctx_id_t ctx) { OM_uint32 major; unsigned char *p = (unsigned char *)token->value; size_t remain = token->length; if (remain < 16) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) { *minor = GSSEAP_BAD_CONTEXT_TOKEN; return GSS_S_DEFECTIVE_TOKEN; } ctx->state = load_uint32_be(&p[4]); ctx->flags = load_uint32_be(&p[8]); ctx->gssFlags = load_uint32_be(&p[12]); p += 16; remain -= 16; /* Validate state */ if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL || GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED) return GSS_S_DEFECTIVE_TOKEN; /* Only acceptor can export partial context tokens */ if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) return GSS_S_DEFECTIVE_TOKEN; major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed); if (GSS_ERROR(major)) return major; major = importKerberosKey(minor, &p, &remain, &ctx->checksumType, &ctx->encryptionType, &ctx->rfc3961Key); if (GSS_ERROR(major)) return major; /* Initiator name OID matches the context mechanism, so it's not encoded */ major = importName(minor, ctx->mechanismUsed, &p, &remain, &ctx->initiatorName); if (GSS_ERROR(major)) return major; major = importName(minor, GSS_C_NO_OID, &p, &remain, &ctx->acceptorName); if (GSS_ERROR(major)) return major; /* Check that, if context is established, names are valid */ if (CTX_IS_ESTABLISHED(ctx) && (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME : ctx->initiatorName == GSS_C_NO_NAME)) { return GSS_S_DEFECTIVE_TOKEN; } if (remain < 24 + sequenceSize(ctx->seqState)) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } ctx->expiryTime = (time_t)load_uint64_be(&p[0]); ctx->sendSeq = load_uint64_be(&p[8]); ctx->recvSeq = load_uint64_be(&p[16]); p += 24; remain -= 24; major = sequenceInternalize(minor, &ctx->seqState, &p, &remain); if (GSS_ERROR(major)) return major; #ifdef GSSEAP_ENABLE_ACCEPTOR /* * The partial context should only be expected for unestablished * acceptor contexts. */ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) && (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { major = gssEapImportPartialContext(minor, &p, &remain, ctx); if (GSS_ERROR(major)) return major; } #ifdef GSSEAP_DEBUG GSSEAP_ASSERT(remain == 0); #endif #endif /* GSSEAP_ENABLE_ACCEPTOR */ major = GSS_S_COMPLETE; *minor = 0; return major; }