aboutsummaryrefslogtreecommitdiff
path: root/src/lib/gssapi/krb5/accept_sec_context.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/krb5/accept_sec_context.c')
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c215
1 files changed, 153 insertions, 62 deletions
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 5ff6146..9db7e7e 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -77,6 +77,12 @@
#endif
#include <assert.h>
+#ifdef CFX_EXERCISE
+#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
+#else
+#define CFX_ACCEPTOR_SUBKEY 1
+#endif
+
/* Decode, decrypt and store the forwarded creds in the local ccache. */
static krb5_error_code
rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
@@ -101,8 +107,8 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
* By the time krb5_rd_cred is called here (after krb5_rd_req has been
* called in krb5_gss_accept_sec_context), the "keyblock" field of
* auth_context contains a pointer to the session key, and the
- * "remote_subkey" field might contain a session subkey. Either of
- * these (the "remote_subkey" if it isn't NULL, otherwise the
+ * "recv_subkey" field might contain a session subkey. Either of
+ * these (the "recv_subkey" if it isn't NULL, otherwise the
* "keyblock") might have been used to encrypt the encrypted part of
* the KRB_CRED message that contains the forwarded credentials. (The
* Java Crypto and Security Implementation from the DSTC in Australia
@@ -122,7 +128,8 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
goto cleanup;
krb5_auth_con_setflags(context, new_auth_ctx, 0);
- if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf, &creds, NULL)))
+ if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
+ &creds, NULL)))
goto cleanup;
}
@@ -241,7 +248,14 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
krb5_data scratch;
gss_cred_id_t cred_handle = NULL;
krb5_gss_cred_id_t deleg_cred = NULL;
+ krb5int_access kaccess;
+ code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (code) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
if (GSS_ERROR(kg_get_context(minor_status, &context)))
return(GSS_S_FAILURE);
@@ -312,13 +326,13 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
if (!(code = g_verify_token_header((gss_OID) gss_mech_krb5,
&(ap_req.length),
&ptr, KG_TOK_CTX_AP_REQ,
- input_token->length))) {
+ input_token->length, 1))) {
mech_used = gss_mech_krb5;
} else if ((code == G_WRONG_MECH) &&
!(code = g_verify_token_header((gss_OID) gss_mech_krb5_old,
&(ap_req.length),
&ptr, KG_TOK_CTX_AP_REQ,
- input_token->length))) {
+ input_token->length, 1))) {
/*
* Previous versions of this library used the old mech_id
* and some broken behavior (wrong IV on checksum
@@ -327,6 +341,11 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
* old behavior.
*/
mech_used = gss_mech_krb5_old;
+ } else if (code == G_WRONG_TOKID) {
+ major_status = GSS_S_CONTINUE_NEEDED;
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
+ mech_used = gss_mech_krb5;
+ goto fail;
} else {
major_status = GSS_S_DEFECTIVE_TOKEN;
goto fail;
@@ -358,8 +377,6 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
major_status = GSS_S_FAILURE;
goto fail;
}
- krb5_auth_con_setflags(context, auth_context,
- KRB5_AUTH_CONTEXT_DO_SEQUENCE);
if (cred->rcache) {
if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
major_status = GSS_S_FAILURE;
@@ -376,6 +393,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
major_status = GSS_S_FAILURE;
goto fail;
}
+ krb5_auth_con_setflags(context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
krb5_auth_con_getauthenticator(context, auth_context, &authdat);
@@ -496,18 +515,20 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
reqcksum.contents = 0;
TREAD_INT(ptr, gss_flags, bigend);
+#if 0
gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if
there's a delegation, we'll set
it below */
+#endif
decode_req_message = 0;
/* if the checksum length > 24, there are options to process */
- if(authdat->checksum->length > 24) {
+ if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
i = authdat->checksum->length - 24;
- while (i >= 4) {
+ if (i >= 4) {
TREAD_INT16(ptr, option_id, bigend);
@@ -515,23 +536,24 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
i -= 4;
- /* have to use ptr2, since option.data is wrong type and
- macro uses ptr as both lvalue and rvalue */
-
if (i < option.length || option.length < 0) {
code = KG_BAD_LENGTH;
major_status = GSS_S_FAILURE;
goto fail;
}
- TREAD_STR(ptr, ptr2, bigend);
+ /* have to use ptr2, since option.data is wrong type and
+ macro uses ptr as both lvalue and rvalue */
+
+ TREAD_STR(ptr, ptr2, option.length);
option.data = (char *) ptr2;
i -= option.length;
- switch(option_id) {
-
- case KRB5_GSS_FOR_CREDS_OPTION:
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
/* store the delegated credential */
@@ -543,16 +565,37 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
goto fail;
}
- gss_flags |= GSS_C_DELEG_FLAG; /* got a delegation */
-
- break;
-
- /* default: */
- /* unknown options aren't an error */
-
- } /* switch */
- } /* while */
- } /* if */
+ } /* if i >= 4 */
+ /* ignore any additional trailing data, for now */
+#ifdef CFX_EXERCISE
+ {
+ FILE *f = fopen("/tmp/gsslog", "a");
+ if (f) {
+ fprintf(f,
+ "initial context token with delegation, %d extra bytes\n",
+ i);
+ fclose(f);
+ }
+ }
+#endif
+ } else {
+#ifdef CFX_EXERCISE
+ {
+ FILE *f = fopen("/tmp/gsslog", "a");
+ if (f) {
+ if (gss_flags & GSS_C_DELEG_FLAG)
+ fprintf(f,
+ "initial context token, delegation flag but too small\n");
+ else
+ /* no deleg flag, length might still be too big */
+ fprintf(f,
+ "initial context token, %d extra bytes\n",
+ authdat->checksum->length - 24);
+ fclose(f);
+ }
+ }
+#endif
+ }
}
/* create the ctx struct and start filling it in */
@@ -568,7 +611,10 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
ctx->mech_used = (gss_OID) mech_used;
ctx->auth_context = auth_context;
ctx->initiate = 0;
- ctx->gss_flags = KG_IMPLFLAGS(gss_flags);
+ ctx->gss_flags = (GSS_C_TRANS_FLAG |
+ ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
ctx->seed_init = 0;
ctx->big_endian = bigend;
@@ -592,8 +638,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
goto fail;
}
- if ((code = krb5_auth_con_getremotesubkey(context, auth_context,
- &ctx->subkey))) {
+ if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
+ &ctx->subkey))) {
major_status = GSS_S_FAILURE;
goto fail;
}
@@ -616,6 +662,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
goto fail;
}
+ ctx->proto = 0;
switch(ctx->subkey->enctype) {
case ENCTYPE_DES_CBC_MD5:
case ENCTYPE_DES_CBC_CRC:
@@ -635,12 +682,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
/*SUPPRESS 113*/
ctx->enc->contents[i] ^= 0xf0;
- if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- break;
+ goto copy_subkey_to_seq;
case ENCTYPE_DES3_CBC_SHA1:
ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
@@ -649,36 +691,38 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
ctx->sealalg = SEAL_ALG_DES3KD;
/* fill in the encryption descriptors */
-
+ copy_subkey:
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
major_status = GSS_S_FAILURE;
goto fail;
}
-
+ copy_subkey_to_seq:
if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
major_status = GSS_S_FAILURE;
goto fail;
}
-
break;
- case ENCTYPE_ARCFOUR_HMAC:
- ctx->signalg = SGN_ALG_HMAC_MD5 ;
- ctx->cksum_size = 8;
- ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
-
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
- if (code)
- goto fail;
- code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
- if (code) {
- krb5_free_keyblock (context, ctx->enc);
- goto fail;
- }
- break;
+
+ case ENCTYPE_ARCFOUR_HMAC:
+ ctx->signalg = SGN_ALG_HMAC_MD5 ;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
+ goto copy_subkey;
default:
- code = KRB5_BAD_ENCTYPE;
- goto fail;
+ ctx->signalg = -1;
+ ctx->sealalg = -1;
+ ctx->proto = 1;
+ code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
+ &ctx->cksumtype);
+ if (code)
+ goto fail;
+ code = krb5_c_checksum_length(context, ctx->cksumtype,
+ &ctx->cksum_size);
+ if (code)
+ goto fail;
+ ctx->have_acceptor_subkey = 0;
+ goto copy_subkey;
}
ctx->endtime = ticket->enc_part2->times.endtime;
@@ -686,7 +730,11 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
krb5_free_ticket(context, ticket); /* Done with ticket */
- krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv);
+ {
+ krb5_ui_4 seq_temp;
+ krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_recv = seq_temp;
+ }
if ((code = krb5_timeofday(context, &now))) {
major_status = GSS_S_FAILURE;
@@ -701,7 +749,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
g_order_init(&(ctx->seqstate), ctx->seq_recv,
(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
- (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0);
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
/* at this point, the entire context structure is filled in,
so it can be released. */
@@ -710,15 +758,56 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
unsigned char * ptr3;
+ krb5_ui_4 seq_temp;
+ int cfx_generate_subkey;
+
+ if (ctx->proto == 1)
+ cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
+ else
+ cfx_generate_subkey = 0;
+
+ if (cfx_generate_subkey) {
+ krb5_int32 acflags;
+ code = krb5_auth_con_getflags(context, auth_context, &acflags);
+ if (code == 0) {
+ acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
+ code = krb5_auth_con_setflags(context, auth_context, acflags);
+ }
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
major_status = GSS_S_FAILURE;
goto fail;
}
- krb5_auth_con_getlocalseqnumber(context, auth_context,
- &ctx->seq_send);
+ krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_send = seq_temp & 0xffffffffL;
+
+ if (cfx_generate_subkey) {
+ /* Get the new acceptor subkey. With the code above, there
+ should always be one if we make it to this point. */
+ code = krb5_auth_con_getsendsubkey(context, auth_context,
+ &ctx->acceptor_subkey);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
+ ctx->acceptor_subkey->enctype,
+ &ctx->acceptor_subkey_cksumtype);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ ctx->have_acceptor_subkey = 1;
+ }
/* the reply token hasn't been sent yet, but that's ok. */
+ ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
ctx->established = 1;
token.length = g_token_size((gss_OID) mech_used, ap_rep.length);
@@ -803,7 +892,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
if (ap_rep.data)
krb5_free_data_contents(context, &ap_rep);
- if (!GSS_ERROR(major_status))
+ if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED)
return(major_status);
/* from here on is the real "fail" code */
@@ -843,7 +932,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
krb5_free_ap_req(context, request);
}
- if (cred && (gss_flags & GSS_C_MUTUAL_FLAG)) {
+ if (cred
+ && ((gss_flags & GSS_C_MUTUAL_FLAG)
+ || (major_status == GSS_S_CONTINUE_NEEDED))) {
unsigned int tmsglen;
int toktype;
@@ -853,7 +944,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
*/
memset(&krb_error_data, 0, sizeof(krb_error_data));
- code -= ERROR_TABLE_BASE_krb5;
+ code -= ERROR_TABLE_BASE_krb5;
if (code < 0 || code > 128)
code = 60 /* KRB_ERR_GENERIC */;
@@ -861,7 +952,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
(void) krb5_us_timeofday(context, &krb_error_data.stime,
&krb_error_data.susec);
krb_error_data.server = cred->princ;
-
+
code = krb5_mk_error(context, &krb_error_data, &scratch);
if (code)
return (major_status);