#include "gssapiP_eap.h"
+#ifdef GSSEAP_ENABLE_REAUTH
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;
-}
-
+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);
+#endif
/*
* Mark a context as ready for cryptographic operations
ctx->encryptionType = ENCTYPE_NULL;
}
- return acceptReadyCommon(minor, ctx, cred);
+ 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;
}
static OM_uint32
if (GSS_ERROR(major))
goto cleanup;
- ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
+ ctx->state = EAP_STATE_EXTENSIONS_REQ;
}
major = GSS_S_CONTINUE_NEEDED;
}
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)
+acceptGssChannelBindings(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings)
{
- OM_uint32 major;
+ OM_uint32 major, tmpMinor;
gss_iov_buffer_desc iov[2];
- outputToken->length = 0;
- outputToken->value = NULL;
-
- 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;
-
- if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
- iov[0].buffer = chanBindings->application_data;
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+ iov[0].buffer.length = 0;
+ iov[0].buffer.value = NULL;
- 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_STREAM;
+ iov[1].buffer = *inputToken;
- 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, 2, TOK_TYPE_WRAP);
+ if (GSS_ERROR(major))
+ return major;
- major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
- iov, 3, TOK_TYPE_GSS_CB);
- if (GSS_ERROR(major))
- return major;
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
+ !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
+ major = GSS_S_BAD_BINDINGS;
+ } else {
+ major = GSS_S_CONTINUE_NEEDED;
}
- ctx->state = EAP_STATE_KRB_REAUTH_CRED;
- return GSS_S_CONTINUE_NEEDED;
+ gss_release_buffer(&tmpMinor, &iov[0].buffer);
+
+ return major;
}
static OM_uint32
-eapGssSmAcceptKrbReauthCred(OM_uint32 *minor,
+eapGssSmAcceptExtensionsReq(OM_uint32 *minor,
gss_ctx_id_t ctx,
gss_cred_id_t cred,
gss_buffer_t inputToken,
{
OM_uint32 major;
- major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
+ outputToken->length = 0;
+ outputToken->value = NULL;
+
+ major = acceptGssChannelBindings(minor, ctx, cred, inputToken,
+ chanBindings);
if (GSS_ERROR(major))
return major;
- ctx->state = EAP_STATE_ESTABLISHED;
+ ctx->state = EAP_STATE_EXTENSIONS_RESP;
- return GSS_S_COMPLETE;
-}
-
-static OM_uint32
-eapGssSmAcceptEstablished(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;
+ return GSS_S_CONTINUE_NEEDED;
}
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)
+eapGssSmAcceptExtensionsResp(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_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;
- }
- }
+ gss_buffer_desc credsToken = GSS_C_EMPTY_BUFFER;
- major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
- &ctx->checksumType);
+#ifdef GSSEAP_ENABLE_REAUTH
+ major = gssEapMakeReauthCreds(minor, ctx, cred, &credsToken);
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;
+ return major;
+#else
+ credsToken.value = "";
+#endif /* GSSEAP_ENABLE_REAUTH */
- 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;
+ major = duplicateBuffer(minor, &credsToken, outputToken);
+ if (GSS_ERROR(major)) {
+ gss_release_buffer(&tmpMinor, &credsToken);
+ return major;
}
- if (timeRec != GSS_C_INDEFINITE)
- ctx->expiryTime = time(NULL) + timeRec;
-
- major = acceptReadyCommon(minor, ctx, cred);
- if (GSS_ERROR(major))
- goto cleanup;
+#ifdef GSSEAP_ENABLE_REAUTH
+ gss_release_buffer(&tmpMinor, &credsToken);
+#endif
ctx->state = EAP_STATE_ESTABLISHED;
- ctx->mechanismUsed = GSS_EAP_MECHANISM;
-
-cleanup:
- gss_release_buffer_set(&tmpMinor, &keyData);
- gss_release_buffer(&tmpMinor, &nameBuf);
- return major;
+ return GSS_S_COMPLETE;
}
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)
+eapGssSmAcceptEstablished(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;
+ /* Called with already established context */
+ *minor = EINVAL;
+ return GSS_S_BAD_STATUS;
}
static struct gss_eap_acceptor_sm {
} 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, eapGssSmAcceptKrbReauthCred },
+ { TOK_TYPE_EXT_REQ, TOK_TYPE_NONE, eapGssSmAcceptExtensionsReq },
+ { TOK_TYPE_NONE, TOK_TYPE_EXT_RESP, eapGssSmAcceptExtensionsResp },
{ TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished },
+#ifdef GSSEAP_ENABLE_REAUTH
{ TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth },
+#endif
};
OM_uint32
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;
if (GSS_ERROR(major))
return major;
+ initialContextToken = 1;
*context_handle = ctx;
}
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;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
ctx->state = EAP_STATE_KRB_REAUTH_GSS;
- } else if (GSS_ERROR(major)) {
+ } else
+#endif
+ 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;
}
if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
}
- if (innerOutputToken.length != 0) {
+ if (innerOutputToken.value != NULL) {
tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
sm->outputTokenType, output_token);
if (GSS_ERROR(tmpMajor)) {
return major;
}
+#ifdef GSSEAP_ENABLE_REAUTH
+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;
+
+ major = gssEapGlueToMechName(minor, initiator, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+ 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
+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 gssFlags, 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,
+ &gssFlags,
+ &timeRec,
+ NULL);
+ if (major == GSS_S_COMPLETE) {
+ major = acceptReadyKrb(minor, ctx, cred,
+ krbInitiator, mech, timeRec);
+ }
+
+ ctx->gssFlags = gssFlags;
+
+ gssReleaseName(&tmpMinor, &krbInitiator);
+
+ return major;
+}
+#endif /* GSSEAP_ENABLE_REAUTH */