/* 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 */
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,
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,
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) {
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;
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;
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;
unsigned int bodysize;
int err;
int toktype2;
+ int vfyflags = 0;
OM_uint32 ret;
/* validate the context handle */
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;
}
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,
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;
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);
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);
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;
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;
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;
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);
/*
/* 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--------------*/
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) {
{
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;
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;
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,
*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;
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;
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;
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;
+}
+
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) {
#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),