From 919383c2c3c95973c3579e6730cdc5c077132c3d Mon Sep 17 00:00:00 2001 From: Sam Hartman Date: Tue, 13 Jan 2009 22:57:42 +0000 Subject: [PATCH] Patch from Luke Howard to: * Accept both CFX and non-CFX tokens all the time on acceptor * Only produce an acceptor subkey if you are using cfx or dce or negotiating up to cfx Additional changes from Sam Hartman: * do not assume that the ticket key type (server key) is a valid target for negotiation: the client may not support it. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21742 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/k5-int.h | 8 ++- src/lib/gssapi/krb5/accept_sec_context.c | 29 ++++++++ src/lib/gssapi/krb5/k5sealv3.c | 5 +- src/lib/gssapi/krb5/k5sealv3iov.c | 5 +- src/lib/gssapi/krb5/k5unseal.c | 40 ++++++++--- src/lib/gssapi/krb5/k5unsealiov.c | 92 +++++++++++++++++------- src/lib/gssapi/krb5/util_crypt.c | 69 ++++++++++++------ src/lib/krb5/krb/auth_con.c | 10 +++ src/lib/krb5/krb/rd_req_dec.c | 1 - src/lib/krb5/os/accessor.c | 1 + 10 files changed, 198 insertions(+), 62 deletions(-) diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 9ad55694e..072a4d397 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -1959,7 +1959,7 @@ void krb5int_free_srv_dns_data(struct srv_dns_entry *); /* To keep happy libraries which are (for now) accessing internal stuff */ /* Make sure to increment by one when changing the struct */ -#define KRB5INT_ACCESS_STRUCT_VERSION 12 +#define KRB5INT_ACCESS_STRUCT_VERSION 13 #ifndef ANAME_SZ struct ktext; /* from krb.h, for krb524 support */ @@ -1972,6 +1972,7 @@ typedef struct _krb5int_access { const krb5_keyblock *key, unsigned int icount, const krb5_data *input, krb5_data *output); + krb5_error_code (* krb5_auth_con_get_subkey_enctype)(krb5_context, krb5_auth_context, krb5_enctype *); /* service location and communication */ krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg, const struct addrlist *, struct sendto_callback_info*, krb5_data *reply, @@ -2580,6 +2581,11 @@ krb5_error_code krb5_auth_con_getpermetypes krb5_auth_context, krb5_enctype **); +krb5_error_code krb5_auth_con_get_subkey_enctype + (krb5_context context, + krb5_auth_context, + krb5_enctype *); + krb5_error_code KRB5_CALLCONV krb5int_server_decrypt_ticket_keyblock (krb5_context context, diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index 2e2433a2a..63ce92c1b 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -395,6 +395,7 @@ kg_accept_krb5(minor_status, context_handle, int cred_rcache = 0; int no_encap = 0; krb5_flags ap_req_options = 0; + krb5_enctype negotiated_etype; code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); if (code) { @@ -903,6 +904,34 @@ kg_accept_krb5(minor_status, context_handle, krb5_int32 seq_temp; int cfx_generate_subkey; + /* + * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX, + * because pre-CFX tokens do not indicate which key to use. (Note that + * DCE_STYLE implies that we will use a subkey.) + */ + if (ctx->proto == 0 && + (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 && + (ap_req_options & AP_OPTS_USE_SUBKEY)) { + code = (*kaccess.krb5_auth_con_get_subkey_enctype) (context, + auth_context, + &negotiated_etype); + if (code != 0) { + major_status = GSS_S_FAILURE; + goto fail; + } + + switch (negotiated_etype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_MD4: + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_DES3_CBC_SHA1: + case ENCTYPE_ARCFOUR_HMAC: + case ENCTYPE_ARCFOUR_HMAC_EXP: + ap_req_options &= ~(AP_OPTS_USE_SUBKEY); + break; + } + } + if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) || (ap_req_options & AP_OPTS_USE_SUBKEY)) cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY; diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c index 71e832e15..56a4a4462 100644 --- a/src/lib/gssapi/krb5/k5sealv3.c +++ b/src/lib/gssapi/krb5/k5sealv3.c @@ -320,8 +320,9 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr, krb5_keyblock *key; krb5_cksumtype cksumtype; - assert(ctx->big_endian == 0); - assert(ctx->proto == 1); + if(ctx->big_endian != 0) + goto defective; + if (qop_state) *qop_state = GSS_C_QOP_DEFAULT; diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c index 41e6132cd..879d99748 100644 --- a/src/lib/gssapi/krb5/k5sealv3iov.c +++ b/src/lib/gssapi/krb5/k5sealv3iov.c @@ -297,8 +297,9 @@ gss_krb5int_unseal_v3_iov(krb5_context context, krb5_cksumtype cksumtype; int conf_flag = 0; - assert(ctx->big_endian == 0); - assert(ctx->proto == 1); + if (ctx->big_endian != 0) + return GSS_S_DEFECTIVE_TOKEN; + if (qop_state != NULL) *qop_state = GSS_C_QOP_DEFAULT; diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c index 4b70fd02a..a94ac9ef0 100644 --- a/src/lib/gssapi/krb5/k5unseal.c +++ b/src/lib/gssapi/krb5/k5unseal.c @@ -494,6 +494,7 @@ kg_unseal(minor_status, context_handle, input_token_buffer, unsigned int bodysize; int err; int toktype2; + int vfyflags = 0; OM_uint32 ret; /* validate the context handle */ @@ -515,26 +516,49 @@ kg_unseal(minor_status, context_handle, input_token_buffer, ptr = (unsigned char *) input_token_buffer->value; - toktype2 = kg_map_toktype(ctx->proto, toktype); err = g_verify_token_header(ctx->mech_used, - &bodysize, &ptr, toktype2, + &bodysize, &ptr, -1, input_token_buffer->length, - !ctx->proto); + vfyflags); if (err) { *minor_status = err; return GSS_S_DEFECTIVE_TOKEN; } - if (ctx->proto == 0) - ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize, - message_buffer, conf_state, qop_state, - toktype); - else + if (bodysize < 2) { + *minor_status = (OM_uint32)G_BAD_TOK_HEADER; + return GSS_S_DEFECTIVE_TOKEN; + } + + toktype2 = load_16_be(ptr); + + ptr += 2; + bodysize -= 2; + + switch (toktype2) { + case KG2_TOK_MIC_MSG: + case KG2_TOK_WRAP_MSG: + case KG2_TOK_DEL_CTX: ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx, ptr, bodysize, message_buffer, conf_state, qop_state, toktype); + break; + case KG_TOK_MIC_MSG: + case KG_TOK_WRAP_MSG: + case KG_TOK_DEL_CTX: + ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize, + message_buffer, conf_state, qop_state, + toktype); + break; + default: + *minor_status = (OM_uint32)G_BAD_TOK_HEADER; + ret = GSS_S_DEFECTIVE_TOKEN; + break; + } + if (ret != 0) save_error_info (*minor_status, ctx->k5_context); + return ret; } diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c index c72e2db39..a9d4c9eff 100644 --- a/src/lib/gssapi/krb5/k5unsealiov.c +++ b/src/lib/gssapi/krb5/k5unsealiov.c @@ -172,7 +172,7 @@ kg_unseal_v1_iov(krb5_context context, iov, iov_count); krb5_free_keyblock(context, enc_key); } else { - code = kg_decrypt_iov(context, ctx->proto, + code = kg_decrypt_iov(context, 0, ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0), 0 /*EC*/, 0 /*RRC*/, ctx->enc, KG_USAGE_SEAL, NULL, @@ -325,8 +325,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status, gss_qop_t *qop_state, gss_iov_buffer_desc *iov, int iov_count, - int toktype, - int toktype2) + int toktype) { krb5_error_code code; krb5_context context = ctx->k5_context; @@ -336,6 +335,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status, gss_iov_buffer_t trailer; size_t input_length; unsigned int bodysize; + int toktype2; int vfyflags = 0; header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); @@ -364,26 +364,46 @@ kg_unseal_iov_token(OM_uint32 *minor_status, input_length += trailer->buffer.length; } - if (ctx->proto == 0) - vfyflags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED; if (ctx->gss_flags & GSS_C_DCE_STYLE) vfyflags |= G_VFY_TOKEN_HDR_IGNORE_SEQ_SIZE; code = g_verify_token_header(ctx->mech_used, - &bodysize, &ptr, toktype2, - input_length, vfyflags); + &bodysize, &ptr, -1, + input_length, 0); if (code != 0) { - *minor_status = code; + *minor_status = code; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (bodysize < 2) { + *minor_status = (OM_uint32)G_BAD_TOK_HEADER; return GSS_S_DEFECTIVE_TOKEN; } - if (ctx->proto == 0) + toktype2 = load_16_be(ptr); + + ptr += 2; + bodysize -= 2; + + switch (toktype2) { + case KG2_TOK_MIC_MSG: + case KG2_TOK_WRAP_MSG: + case KG2_TOK_DEL_CTX: + code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count, + conf_state, qop_state, toktype); + break; + case KG_TOK_MIC_MSG: + case KG_TOK_WRAP_MSG: + case KG_TOK_DEL_CTX: code = kg_unseal_v1_iov(context, minor_status, ctx, iov, iov_count, (size_t)(ptr - (unsigned char *)header->buffer.value), conf_state, qop_state, toktype); - else - code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count, - conf_state, qop_state, toktype); + break; + default: + *minor_status = (OM_uint32)G_BAD_TOK_HEADER; + code = GSS_S_DEFECTIVE_TOKEN; + break; + } if (code != 0) save_error_info(*minor_status, context); @@ -402,21 +422,19 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, gss_qop_t *qop_state, gss_iov_buffer_desc *iov, int iov_count, - int toktype, - int toktype2) + int toktype) { unsigned char *ptr; unsigned int bodysize; OM_uint32 code = 0, major_status = GSS_S_FAILURE; krb5_context context = ctx->k5_context; - int conf_req_flag; + int conf_req_flag, toktype2; int i = 0, j; gss_iov_buffer_desc *tiov = NULL; gss_iov_buffer_t stream, data = NULL; gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer; assert(toktype == KG_TOK_WRAP_MSG); - assert(toktype2 == KG_TOK_WRAP_MSG || toktype2 == KG2_TOK_WRAP_MSG); if (toktype != KG_TOK_WRAP_MSG || (ctx->gss_flags & GSS_C_DCE_STYLE)) { code = EINVAL; @@ -429,14 +447,23 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, ptr = (unsigned char *)stream->buffer.value; code = g_verify_token_header(ctx->mech_used, - &bodysize, &ptr, toktype2, - stream->buffer.length, - ctx->proto ? 0 : G_VFY_TOKEN_HDR_WRAPPER_REQUIRED); + &bodysize, &ptr, -1, + stream->buffer.length, 0); if (code != 0) { major_status = GSS_S_DEFECTIVE_TOKEN; goto cleanup; } + if (bodysize < 2) { + *minor_status = (OM_uint32)G_BAD_TOK_HEADER; + return GSS_S_DEFECTIVE_TOKEN; + } + + toktype2 = load_16_be(ptr); + + ptr += 2; + bodysize -= 2; + tiov = (gss_iov_buffer_desc *)calloc((size_t)iov_count + 2, sizeof(gss_iov_buffer_desc)); if (tiov == NULL) { code = ENOMEM; @@ -489,7 +516,10 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, ttrailer = &tiov[i++]; ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER; - if (ctx->proto == 1) { + switch (toktype2) { + case KG2_TOK_MIC_MSG: + case KG2_TOK_WRAP_MSG: + case KG2_TOK_DEL_CTX: { size_t ec, rrc; krb5_enctype enctype = ctx->enc->enctype; unsigned int k5_headerlen = 0; @@ -525,7 +555,11 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + k5_trailerlen; ttrailer->buffer.value = (unsigned char *)stream->buffer.value + stream->buffer.length - ttrailer->buffer.length; - } else { + break; + } + case KG_TOK_MIC_MSG: + case KG_TOK_WRAP_MSG: + case KG_TOK_DEL_CTX: theader->buffer.length += ctx->cksum_size + kg_confounder_size(context, ctx->enc); /* @@ -538,6 +572,13 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, /* no TRAILER for pre-CFX */ ttrailer->buffer.length = 0; ttrailer->buffer.value = NULL; + + break; + default: + code = (OM_uint32)G_BAD_TOK_HEADER; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + break; } /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/ @@ -573,7 +614,7 @@ kg_unseal_stream_iov(OM_uint32 *minor_status, assert(i <= iov_count + 2); major_status = kg_unseal_iov_token(&code, ctx, conf_state, qop_state, - tiov, i, toktype, toktype2); + tiov, i, toktype); if (major_status == GSS_S_COMPLETE) *data = *tdata; else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { @@ -603,7 +644,6 @@ kg_unseal_iov(OM_uint32 *minor_status, { krb5_gss_ctx_id_rec *ctx; OM_uint32 code; - int toktype2; if (!kg_validate_ctx_id(context_handle)) { *minor_status = (OM_uint32)G_VALIDATE_FAILED; @@ -616,14 +656,12 @@ kg_unseal_iov(OM_uint32 *minor_status, return GSS_S_NO_CONTEXT; } - toktype2 = kg_map_toktype(ctx->proto, toktype); - if (kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) { code = kg_unseal_stream_iov(minor_status, ctx, conf_state, qop_state, - iov, iov_count, toktype, toktype2); + iov, iov_count, toktype); } else { code = kg_unseal_iov_token(minor_status, ctx, conf_state, qop_state, - iov, iov_count, toktype, toktype2); + iov, iov_count, toktype); } return code; diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c index d718ae0b1..e93acb9ca 100644 --- a/src/lib/gssapi/krb5/util_crypt.c +++ b/src/lib/gssapi/krb5/util_crypt.c @@ -56,6 +56,34 @@ const char const kg_arcfour_l40[] = "fortybits"; +static krb5_error_code +kg_copy_keys(krb5_context context, + krb5_gss_ctx_id_rec *ctx, + krb5_keyblock *subkey) +{ + krb5_error_code code; + + if (ctx->enc != NULL) { + krb5_free_keyblock(context, ctx->enc); + ctx->enc = NULL; + } + + code = krb5_copy_keyblock(context, subkey, &ctx->enc); + if (code != 0) + return code; + + if (ctx->seq != NULL) { + krb5_free_keyblock(context, ctx->seq); + ctx->seq = NULL; + } + + code = krb5_copy_keyblock(context, subkey, &ctx->seq); + if (code != 0) + return code; + + return 0; +} + krb5_error_code kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, @@ -71,31 +99,28 @@ kg_setup_keys(krb5_context context, *cksumtype = 0; ctx->proto = 0; - - code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); - if (code != 0) - return code; - - if (ctx->enc != NULL) { - krb5_free_keyblock(context, ctx->enc); - ctx->enc = NULL; + if (ctx->enc == NULL) { + ctx->signalg = -1; + ctx->sealalg = -1; } - code = krb5_copy_keyblock(context, subkey, &ctx->enc); + + code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); if (code != 0) return code; - if (ctx->seq != NULL) { - krb5_free_keyblock(context, ctx->seq); - ctx->seq = NULL; - } - code = krb5_copy_keyblock(context, subkey, &ctx->seq); + code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, subkey->enctype, + cksumtype); if (code != 0) - return code; + return code; switch (subkey->enctype) { case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: case ENCTYPE_DES_CBC_CRC: + code = kg_copy_keys(context, ctx, subkey); + if (code != 0) + return code; + ctx->enc->enctype = ENCTYPE_DES_CBC_RAW; ctx->seq->enctype = ENCTYPE_DES_CBC_RAW; ctx->signalg = SGN_ALG_DES_MAC_MD5; @@ -107,6 +132,10 @@ kg_setup_keys(krb5_context context, ctx->enc->contents[i] ^= 0xF0; break; case ENCTYPE_DES3_CBC_SHA1: + code = kg_copy_keys(context, ctx, subkey); + if (code != 0) + return code; + ctx->enc->enctype = ENCTYPE_DES3_CBC_RAW; ctx->seq->enctype = ENCTYPE_DES3_CBC_RAW; ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; @@ -115,19 +144,17 @@ kg_setup_keys(krb5_context context, break; case ENCTYPE_ARCFOUR_HMAC: case ENCTYPE_ARCFOUR_HMAC_EXP: + code = kg_copy_keys(context, ctx, subkey); + if (code != 0) + return code; + ctx->signalg = SGN_ALG_HMAC_MD5; ctx->cksum_size = 8; ctx->sealalg = SEAL_ALG_MICROSOFT_RC4; break; default: - ctx->signalg = -1; - ctx->sealalg = -1; ctx->proto = 1; - code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, subkey->enctype, - cksumtype); - if (code != 0) - return code; } return 0; diff --git a/src/lib/krb5/krb/auth_con.c b/src/lib/krb5/krb/auth_con.c index 7c1858553..7af96403f 100644 --- a/src/lib/krb5/krb/auth_con.c +++ b/src/lib/krb5/krb/auth_con.c @@ -556,3 +556,13 @@ chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq) else return 0; } + +krb5_error_code +krb5_auth_con_get_subkey_enctype(krb5_context context, + krb5_auth_context auth_context, + krb5_enctype *etype) +{ + *etype = auth_context->negotiated_etype; + return 0; +} + diff --git a/src/lib/krb5/krb/rd_req_dec.c b/src/lib/krb5/krb/rd_req_dec.c index 2e64233fd..618151100 100644 --- a/src/lib/krb5/krb/rd_req_dec.c +++ b/src/lib/krb5/krb/rd_req_dec.c @@ -427,7 +427,6 @@ krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype; } desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype; - desired_etypes[desired_etypes_len++] = req->ticket->enc_part.enctype; desired_etypes[desired_etypes_len] = ENCTYPE_NULL; if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) { diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index cdbb59841..1bf171a6f 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -53,6 +53,7 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version) #endif S (free_addrlist, krb5int_free_addrlist), S (krb5_hmac, krb5_hmac), + S (krb5_auth_con_get_subkey_enctype, krb5_auth_con_get_subkey_enctype), S (md5_hash_provider, &krb5int_hash_md5), S (arcfour_enc_provider, &krb5int_enc_arcfour), S (sendto_udp, &krb5int_sendto), -- 2.26.2