summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/k5-int.h8
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c29
-rw-r--r--src/lib/gssapi/krb5/k5sealv3.c5
-rw-r--r--src/lib/gssapi/krb5/k5sealv3iov.c5
-rw-r--r--src/lib/gssapi/krb5/k5unseal.c40
-rw-r--r--src/lib/gssapi/krb5/k5unsealiov.c92
-rw-r--r--src/lib/gssapi/krb5/util_crypt.c69
-rw-r--r--src/lib/krb5/krb/auth_con.c10
-rw-r--r--src/lib/krb5/krb/rd_req_dec.c1
-rw-r--r--src/lib/krb5/os/accessor.c1
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),