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;
&krbInitiator,
&mech,
outputToken,
- &ctx->gssFlags,
+ &gssFlags,
&timeRec,
NULL);
if (major == GSS_S_COMPLETE) {
krbInitiator, mech, timeRec);
}
+ ctx->gssFlags = gssFlags & ~(GSS_C_DCE_STYLE);
+
gssReleaseName(&tmpMinor, &krbInitiator);
return major;
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;
+
+ 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;
}
return major;
}
-
gss_iov_buffer_desc *iov,
int iov_count);
+unsigned char
+rfc4121Flags(gss_ctx_id_t ctx, int receiving);
+
#endif /* _GSSAPIP_EAP_H_ */
}
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))
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;
}
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,
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;
&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);
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;
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;
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)
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;
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
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 */
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)
{
}
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))
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;
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,
goto cleanup;
code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
+ if (code != 0)
goto cleanup;
krb5_free_principal(krbContext, cred->name->krbPrincipal);
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;
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
if (GSS_ERROR(major))
goto cleanup;
- ctx->mechanismUsed = GSS_EAP_MECHANISM;
major = GSS_S_COMPLETE;
cleanup:
return major;
}
-
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;
*minor = 0;
+ if (ret_tok_type != NULL)
+ *ret_tok_type = TOK_TYPE_NONE;
+
if ((toksize -= 1) < 0)
return GSS_S_DEFECTIVE_TOKEN;
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;
#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,
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;
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:
/* 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 */
/* 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) {