From: Sam Hartman Date: Fri, 3 Apr 2009 04:03:45 +0000 (+0000) Subject: Merge fast branch at 22166 onto trunk X-Git-Tag: krb5-1.8-alpha1~570 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4e609bf313a80dbc2247a73d1303b2068eec9acd;p=krb5.git Merge fast branch at 22166 onto trunk ticket: 6436 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22167 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/k5-int.h b/src/include/k5-int.h index db3976057..5e159d9a4 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -982,7 +982,7 @@ typedef struct _krb5_fast_armored_req { typedef struct _krb5_fast_req { krb5_magic magic; - krb5_int32 fast_options; + krb5_flags fast_options; /* padata from req_body is used*/ krb5_kdc_req *req_body; } krb5_fast_req; @@ -1001,7 +1001,7 @@ typedef struct _krb5_fast_finished { typedef struct _krb5_fast_response { krb5_magic magic; krb5_pa_data **padata; - krb5_keyblock *rep_key; + krb5_keyblock *strengthen_key; krb5_fast_finished *finished; krb5_int32 nonce; } krb5_fast_response; diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 7b590f4e0..4f1715d67 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -119,6 +119,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, krb5_keylist_node *tmp_mkey_list; struct kdc_request_state *state = NULL; krb5_data encoded_req_body; + krb5_keyblock *as_encrypting_key = NULL; #if APPLE_PKINIT @@ -592,7 +593,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, goto errout; } ticket_reply.enc_part.kvno = server_key->key_data_kvno; - errcode = kdc_fast_response_handle_padata(state, request, &reply); + errcode = kdc_fast_response_handle_padata(state, request, &reply, client_keyblock.enctype); if (errcode) { status = "fast response handling"; goto errout; @@ -602,8 +603,13 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, reply.enc_part.enctype = client_keyblock.enctype; - errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, - 0, &client_keyblock, &reply, response); + errcode = kdc_fast_handle_reply_key(state, &client_keyblock, &as_encrypting_key); + if (errcode) { + status = "generating reply key"; + goto errout; + } + errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, + 0, as_encrypting_key, &reply, response); reply.enc_part.kvno = client_key->key_data_kvno; if (errcode) { status = "ENCODE_KDC_REP"; @@ -637,7 +643,8 @@ errout: egress: if (pa_context) free_padata_context(kdc_context, &pa_context); - + if (as_encrypting_key) + krb5_free_keyblock(kdc_context, as_encrypting_key); if (errcode) emsg = krb5_get_error_message(kdc_context, errcode); @@ -760,7 +767,7 @@ prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request, int e if (pa == NULL) retval = ENOMEM; else for (size = 0; td[size]; size++) { - krb5_pa_data *pad = malloc(sizeof(krb5_pa_data *)); + krb5_pa_data *pad = malloc(sizeof(krb5_pa_data )); if (pad == NULL) { retval = ENOMEM; break; diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index e06d94dfc..598c87971 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -878,7 +878,8 @@ tgt_again: reply.enc_part.enctype = subkey ? subkey->enctype : header_ticket->enc_part2->session->enctype; - errcode = kdc_fast_response_handle_padata(state, request, &reply); + errcode = kdc_fast_response_handle_padata(state, request, &reply, + subkey?subkey->enctype:header_ticket->enc_part2->session->enctype); if (errcode !=0 ) { status = "Preparing FAST padata"; goto cleanup; @@ -972,7 +973,7 @@ prepare_error_tgs (struct kdc_request_state *state, krb5_data **response, const char *status) { krb5_error errpkt; - krb5_error_code retval; + krb5_error_code retval = 0; krb5_data *scratch; errpkt.ctime = request->nonce; @@ -997,7 +998,8 @@ prepare_error_tgs (struct kdc_request_state *state, } errpkt.e_data.length = 0; errpkt.e_data.data = NULL; - retval = kdc_fast_handle_error(kdc_context, state, request, NULL, &errpkt); + if (state) + retval = kdc_fast_handle_error(kdc_context, state, request, NULL, &errpkt); if (retval) { free(scratch); free(errpkt.text.data); diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c index 10d1d3eb6..ac6aa22c4 100644 --- a/src/kdc/fast_util.c +++ b/src/kdc/fast_util.c @@ -50,7 +50,7 @@ static krb5_error_code armor_ap_request krb5_ticket *ticket = NULL; krb5_keyblock *subkey = NULL; - assert(armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST); + assert(armor->armor_type == KRB5_FAST_ARMOR_AP_REQUEST); krb5_clear_error_message(kdc_context); retval = krb5_auth_con_init(kdc_context, &authcontext); if (retval == 0) @@ -251,8 +251,8 @@ void kdc_free_rstate return; if (s->armor_key) krb5_free_keyblock(kdc_context, s->armor_key); - if (s->reply_key) - krb5_free_keyblock(kdc_context, s->reply_key); + if (s->strengthen_key) + krb5_free_keyblock(kdc_context, s->strengthen_key); if (s->cookie) { free(s->cookie->contents); free(s->cookie); @@ -263,24 +263,33 @@ void kdc_free_rstate krb5_error_code kdc_fast_response_handle_padata (struct kdc_request_state *state, krb5_kdc_req *request, - krb5_kdc_rep *rep) + krb5_kdc_rep *rep, krb5_enctype enctype) { krb5_error_code retval = 0; krb5_fast_finished finish; krb5_fast_response fast_response; krb5_data *encoded_ticket = NULL; krb5_data *encrypted_reply = NULL; - krb5_pa_data *pa = NULL, **pa_array; + krb5_pa_data *pa = NULL, **pa_array = NULL; krb5_cksumtype cksumtype = CKSUMTYPE_RSA_MD5; krb5_pa_data *empty_padata[] = {NULL}; + krb5_keyblock *strengthen_key = NULL; if (!state->armor_key) return 0; memset(&finish, 0, sizeof(finish)); + retval = krb5_init_keyblock(kdc_context, enctype, 0, &strengthen_key); + if (retval == 0) + retval = krb5_c_make_random_key(kdc_context, enctype, strengthen_key); + if (retval == 0) { + state->strengthen_key = strengthen_key; + strengthen_key = NULL; + } + fast_response.padata = rep->padata; if (fast_response.padata == NULL) fast_response.padata = &empty_padata[0]; - fast_response.rep_key = state->reply_key; + fast_response.strengthen_key = state->strengthen_key; fast_response.nonce = request->nonce; fast_response.finished = &finish; finish.client = rep->client; @@ -309,15 +318,20 @@ krb5_error_code kdc_fast_response_handle_padata pa_array[0] = &pa[0]; rep->padata = pa_array; pa_array = NULL; + free(encrypted_reply); encrypted_reply = NULL; pa = NULL; } if (pa) free(pa); + if (pa_array) + free(pa_array); if (encrypted_reply) krb5_free_data(kdc_context, encrypted_reply); if (encoded_ticket) krb5_free_data(kdc_context, encoded_ticket); + if (strengthen_key != NULL) + krb5_free_keyblock(kdc_context, strengthen_key); if (finish.ticket_checksum.contents) krb5_free_checksum_contents(kdc_context, &finish.ticket_checksum); return retval; @@ -339,8 +353,8 @@ krb5_error_code kdc_fast_handle_error krb5_fast_response resp; krb5_error fx_error; krb5_data *encoded_fx_error = NULL, *encrypted_reply = NULL; - krb5_pa_data pa[2]; - krb5_pa_data *outer_pa[3]; + krb5_pa_data pa[1]; + krb5_pa_data *outer_pa[3], *cookie = NULL; krb5_pa_data **inner_pa = NULL; size_t size = 0; krb5_data *encoded_e_data = NULL; @@ -366,15 +380,26 @@ krb5_error_code kdc_fast_handle_error pa[0].length = encoded_fx_error->length; pa[0].contents = (unsigned char *) encoded_fx_error->data; inner_pa[size++] = &pa[0]; - resp.padata = inner_pa; + if (find_pa_data(inner_pa, KRB5_PADATA_FX_COOKIE) == NULL) + retval = kdc_preauth_get_cookie(state, &cookie); + } + if (cookie != NULL) + inner_pa[size++] = cookie; + if (retval == 0) { + resp.padata = inner_pa; resp.nonce = request->nonce; - resp.rep_key = NULL; + resp.strengthen_key = NULL; resp.finished = NULL; } if (retval == 0) retval = encrypt_fast_reply(state, &resp, &encrypted_reply); if (inner_pa) free(inner_pa); /*contained storage from caller and our stack*/ + if (cookie) { + free(cookie->contents); + free(cookie); + cookie = NULL; + } if (retval == 0) { pa[0].pa_type = KRB5_PADATA_FX_FAST; pa[0].length = encrypted_reply->length; @@ -396,3 +421,45 @@ krb5_error_code kdc_fast_handle_error krb5_free_data(kdc_context, encoded_fx_error); return retval; } + +krb5_error_code kdc_fast_handle_reply_key(struct kdc_request_state *state, + krb5_keyblock *existing_key, + krb5_keyblock **out_key) +{ + krb5_error_code retval = 0; + if (state->armor_key) + retval = krb5_c_fx_cf2_simple(kdc_context, + state->strengthen_key, "strengthenkey", + existing_key, + "replykey", out_key); + else retval = krb5_copy_keyblock(kdc_context, existing_key, out_key); + return retval; +} + + +krb5_error_code kdc_preauth_get_cookie(struct kdc_request_state *state, + krb5_pa_data **cookie) +{ + char *contents; + krb5_pa_data *pa = NULL; + /* In our current implementation, the only purpose served by + * returning a cookie is to indicate that a conversation should + * continue on error. Thus, the cookie can have a constant + * string. If cookies are used for real, versioning so that KDCs + * can be upgraded, keying, expiration and many other issues need + * to be considered. + */ + contents = strdup("MIT"); + if (contents == NULL) + return ENOMEM; + pa = calloc(1, sizeof(krb5_pa_data)); + if (pa == NULL) { + free(contents); + return ENOMEM; + } + pa->pa_type = KRB5_PADATA_FX_COOKIE; + pa->length = strlen(contents); + pa->contents = (unsigned char *) contents; + *cookie = pa; + return 0; +} diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index cf269753d..3dda38150 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -289,6 +289,17 @@ static krb5_preauth_systems static_preauth_systems[] = { verify_enc_timestamp, 0 }, + { + "FAST", + KRB5_PADATA_FX_FAST, + PA_HARDWARE, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 + }, { "etype-info", KRB5_PADATA_ETYPE_INFO, @@ -961,7 +972,8 @@ void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client, e_data->data = 0; hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH); - pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+1)); + /* Allocate 1 entry for the terminator and one for the cookie*/ + pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+21)); if (pa_data == 0) return; memset(pa_data, 0, sizeof(krb5_pa_data *) * (n_preauth_systems+1)); @@ -995,6 +1007,8 @@ void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client, "%spreauth required but hint list is empty", hw_only ? "hw" : ""); } +/* If we fail to get the cookie it is probably still reasonable to continue with the response*/ + kdc_preauth_get_cookie(request->kdc_state, pa); retval = encode_krb5_padata_sequence(pa_data, &edat); if (retval) goto errout; diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 08d84db68..8e531f03b 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -347,13 +347,13 @@ kdc_process_tgs_req(krb5_kdc_req *request, const krb5_fulladdr *from, authenticator->authorization_data, KRB5_AUTHDATA_FX_ARMOR, &authdata); if (retval != 0) - goto cleanup_auth_context; + goto cleanup_authenticator; if (authdata&& authdata[0]) { krb5_set_error_message(kdc_context, KRB5KDC_ERR_POLICY, "ticket valid only as FAST armor"); retval = KRB5KDC_ERR_POLICY; krb5_free_authdata(kdc_context, authdata); - goto cleanup_auth_context; + goto cleanup_authenticator; } krb5_free_authdata(kdc_context, authdata); diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 90de8d39b..060442604 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -302,11 +302,12 @@ void log_tgs_alt_tgt(krb5_principal p); struct kdc_request_state { krb5_keyblock *armor_key; - krb5_keyblock *reply_key; /*When replaced by FAST*/ + krb5_keyblock *strengthen_key; krb5_pa_data *cookie; krb5_int32 fast_options; krb5_int32 fast_internal_flags; }; + krb5_error_code kdc_make_rstate(struct kdc_request_state **out); void kdc_free_rstate (struct kdc_request_state *s); @@ -325,12 +326,21 @@ krb5_error_code kdc_find_fast krb5_error_code kdc_fast_response_handle_padata (struct kdc_request_state *state, krb5_kdc_req *request, - krb5_kdc_rep *rep); + krb5_kdc_rep *rep, + krb5_enctype enctype); krb5_error_code kdc_fast_handle_error (krb5_context context, struct kdc_request_state *state, krb5_kdc_req *request, krb5_pa_data **in_padata, krb5_error *err); +krb5_error_code kdc_fast_handle_reply_key(struct kdc_request_state *state, + krb5_keyblock *existing_key, + krb5_keyblock **out_key); + + +krb5_error_code kdc_preauth_get_cookie(struct kdc_request_state *state, + krb5_pa_data **cookie); + diff --git a/src/lib/crypto/arcfour/arcfour.c b/src/lib/crypto/arcfour/arcfour.c index ea3129688..8d35d7eef 100644 --- a/src/lib/crypto/arcfour/arcfour.c +++ b/src/lib/crypto/arcfour/arcfour.c @@ -8,6 +8,8 @@ of RSA Data Security) */ #include "k5-int.h" #include "arcfour-int.h" +#include "../hash_provider/hash_provider.h" + const char *const krb5int_arcfour_l40 = "fortybits"; void @@ -304,3 +306,12 @@ krb5_arcfour_decrypt(const struct krb5_enc_provider *enc, return (ret); } + krb5_error_code krb5int_arcfour_prf( + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + const krb5_data *in, krb5_data *out) + { + assert(out->length == 20); + return krb5_hmac(&krb5int_hash_sha1, key, 1, in, out); + } diff --git a/src/lib/crypto/arcfour/arcfour.h b/src/lib/crypto/arcfour/arcfour.h index e8ff203ca..be408febc 100644 --- a/src/lib/crypto/arcfour/arcfour.h +++ b/src/lib/crypto/arcfour/arcfour.h @@ -34,5 +34,10 @@ extern krb5_error_code krb5int_arcfour_string_to_key( extern const struct krb5_enc_provider krb5int_enc_arcfour; extern const struct krb5_aead_provider krb5int_aead_arcfour; + krb5_error_code krb5int_arcfour_prf( + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + const krb5_data *in, krb5_data *out); #endif /* ARCFOUR_H */ diff --git a/src/lib/crypto/etypes.c b/src/lib/crypto/etypes.c index e7f547b91..debf585fa 100644 --- a/src/lib/crypto/etypes.c +++ b/src/lib/crypto/etypes.c @@ -119,10 +119,10 @@ const struct krb5_keytypes krb5_enctypes_list[] = { "ArcFour with HMAC/md5", &krb5int_enc_arcfour, &krb5int_hash_md5, - 0, + 20, krb5_arcfour_encrypt_length, krb5_arcfour_encrypt, krb5_arcfour_decrypt, krb5int_arcfour_string_to_key, - NULL, /*PRF*/ + krb5int_arcfour_prf, /*PRF*/ CKSUMTYPE_HMAC_MD5_ARCFOUR, &krb5int_aead_arcfour, 0 /*flags*/ }, @@ -131,10 +131,10 @@ const struct krb5_keytypes krb5_enctypes_list[] = { "Exportable ArcFour with HMAC/md5", &krb5int_enc_arcfour, &krb5int_hash_md5, - 0, + 20, krb5_arcfour_encrypt_length, krb5_arcfour_encrypt, krb5_arcfour_decrypt, krb5int_arcfour_string_to_key, - NULL, /*PRF*/ + krb5int_arcfour_prf, /*PRF*/ CKSUMTYPE_HMAC_MD5_ARCFOUR, &krb5int_aead_arcfour, ETYPE_WEAK diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index efa75643d..ed01b7560 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -1211,7 +1211,7 @@ DEFFIELDTYPE(fast_req_padata, krb5_kdc_req, DEFPTRTYPE(ptr_fast_req_padata, fast_req_padata); static const struct field_info fast_req_fields[] = { - FIELDOF_NORM(krb5_fast_req, int32, fast_options, 0), + FIELDOF_NORM(krb5_fast_req, krb5_flags, fast_options, 0), FIELDOF_NORM( krb5_fast_req, ptr_fast_req_padata, req_body, 1), FIELDOF_NORM( krb5_fast_req, ptr_kdc_req_body, req_body, 2), }; @@ -1233,7 +1233,7 @@ DEFPTRTYPE( ptr_fast_finished, fast_finished); static const struct field_info fast_response_fields[] = { FIELDOF_NORM(krb5_fast_response, ptr_seqof_pa_data, padata, 0), - FIELDOF_OPT( krb5_fast_response, ptr_encryption_key, rep_key, 1, 1), + FIELDOF_OPT( krb5_fast_response, ptr_encryption_key, strengthen_key, 1, 1), FIELDOF_OPT( krb5_fast_response, ptr_fast_finished, finished, 2, 2), FIELDOF_NORM(krb5_fast_response, int32, nonce, 3), }; @@ -1242,7 +1242,7 @@ static unsigned int fast_response_optional (const void *p) { unsigned int optional = 0; const krb5_fast_response *val = p; - if (val->rep_key) + if (val->strengthen_key) optional |= (1u <<1); if (val->finished) optional |= (1u<<2); diff --git a/src/lib/krb5/asn.1/krb5_decode.c b/src/lib/krb5/asn.1/krb5_decode.c index 9080d97ec..7a08ec888 100644 --- a/src/lib/krb5/asn.1/krb5_decode.c +++ b/src/lib/krb5/asn.1/krb5_decode.c @@ -1114,7 +1114,7 @@ krb5_error_code decode_krb5_fast_req alloc_field(rep->req_body); clear_field(rep, req_body->padata); {begin_structure(); - get_field(rep->fast_options, 0, asn1_decode_int32); + get_field(rep->fast_options, 0, asn1_decode_krb5_flags); opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data); get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body); end_structure(); } @@ -1137,10 +1137,10 @@ krb5_error_code decode_krb5_fast_response alloc_field(rep); clear_field(rep, finished); clear_field(rep, padata); - clear_field(rep,rep_key); + clear_field(rep,strengthen_key); {begin_structure(); get_field(rep->padata, 0, asn1_decode_sequence_of_pa_data); - opt_field(rep->rep_key, 1, asn1_decode_encryption_key_ptr); + opt_field(rep->strengthen_key, 1, asn1_decode_encryption_key_ptr); opt_field(rep->finished, 2, asn1_decode_fast_finished_ptr); get_field(rep->nonce, 3, asn1_decode_int32); end_structure(); } diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index acc18f6f4..c5256b313 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -271,6 +271,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/srv_dec_tkt.c \ $(srcdir)/srv_rcache.c \ $(srcdir)/str_conv.c \ + $(srcdir)/t_ad_fx_armor.c \ $(srcdir)/tgtname.c \ $(srcdir)/unparse.c \ $(srcdir)/valid_times.c \ @@ -317,6 +318,9 @@ T_PRINC_OBJS= t_princ.o parse.o unparse.o t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_walk_rtree $(T_WALK_RTREE_OBJS) $(KRB5_BASE_LIBS) +t_ad_fx_armor: t_ad_fx_armor.o + $(CC_LINK) -o $@ $< $(KRB5_BASE_LIBS) + t_authdata: t_authdata.o copy_auth.o $(CC_LINK) -o $@ $< copy_auth.o $(KRB5_BASE_LIBS) diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c index e9f54be78..ef57e6d83 100644 --- a/src/lib/krb5/krb/fast.c +++ b/src/lib/krb5/krb/fast.c @@ -299,6 +299,8 @@ static krb5_error_code decrypt_fast_reply free(scratch.data); if (encrypted_response) krb5_free_enc_data(context, encrypted_response); + if (local_resp) + krb5_free_fast_response(context, local_resp); return retval; } @@ -376,9 +378,11 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta fast_response->padata = NULL; /* * If there is more than the fx_error padata, then we want - * to retry the error + * to retry the error if a cookie is present */ *retry = (*out_padata)[1] != NULL; + if (krb5int_find_pa_data(context, *out_padata, KRB5_PADATA_FX_COOKIE) == NULL) + *retry = 0; } if (fx_error) krb5_free_error(context, fx_error); @@ -408,14 +412,14 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta krb5_error_code krb5int_fast_process_response (krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_rep *resp, - krb5_keyblock **as_key) + krb5_keyblock **strengthen_key) { krb5_error_code retval = 0; krb5_fast_response *fast_response = NULL; krb5_data *encoded_ticket = NULL; krb5_boolean cksum_valid; krb5_clear_error_message(context); - *as_key = NULL; + *strengthen_key = NULL; if (state->armor_key == 0) return 0; retval = decrypt_fast_reply(context, state, resp->padata, @@ -442,8 +446,8 @@ krb5_error_code krb5int_fast_process_response krb5_free_principal(context, resp->client); resp->client = fast_response->finished->client; fast_response->finished->client = NULL; - *as_key = fast_response->rep_key; - fast_response->rep_key = NULL; + *strengthen_key = fast_response->strengthen_key; + fast_response->strengthen_key = NULL; krb5_free_pa_data(context, resp->padata); resp->padata = fast_response->padata; fast_response->padata = NULL; @@ -454,6 +458,29 @@ krb5_error_code krb5int_fast_process_response krb5_free_data(context, encoded_ticket); return retval; } + +krb5_error_code krb5int_fast_reply_key(krb5_context context, + krb5_keyblock *strengthen_key, + krb5_keyblock *existing_key, + krb5_keyblock *out_key) +{ + krb5_keyblock *key = NULL; + krb5_error_code retval = 0; + krb5_free_keyblock_contents(context, out_key); + if (strengthen_key) { + retval = krb5_c_fx_cf2_simple(context, strengthen_key, + "strengthenkey", existing_key, "replykey", &key); + if (retval == 0) { + *out_key = *key; + free(key); + } + } else { + retval = krb5_copy_keyblock_contents(context, existing_key, out_key); + } + return retval; +} + + krb5_error_code krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state) { @@ -473,11 +500,6 @@ krb5int_fast_free_state( krb5_context context, struct krb5int_fast_request_state /*We are responsible for none of the store in the fast_outer_req*/ krb5_free_keyblock(context, state->armor_key); krb5_free_fast_armor(context, state->armor); - if (state->cookie) { - free(state->cookie->contents); - free(state->cookie); - state->cookie = NULL; - } free(state); } diff --git a/src/lib/krb5/krb/fast.h b/src/lib/krb5/krb/fast.h index e21df6504..4cc142335 100644 --- a/src/lib/krb5/krb/fast.h +++ b/src/lib/krb5/krb/fast.h @@ -38,7 +38,6 @@ struct krb5int_fast_request_state { krb5_fast_armor *armor; krb5_ui_4 fast_state_flags; krb5_ui_4 fast_options; - krb5_pa_data *cookie; krb5_int32 nonce; }; @@ -61,7 +60,7 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta krb5_error_code krb5int_fast_process_response (krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_rep *resp, - krb5_keyblock **as_key); + krb5_keyblock **strengthen_key); krb5_error_code krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state); @@ -73,5 +72,11 @@ krb5_error_code krb5int_fast_as_armor krb5_gic_opt_ext *opte, krb5_kdc_req *request); +krb5_error_code krb5int_fast_reply_key(krb5_context context, + krb5_keyblock *strengthen_key, + krb5_keyblock *existing_key, + krb5_keyblock *output_key); + + #endif diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 30a38cdae..2944652ff 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -967,8 +967,8 @@ krb5_get_init_creds(krb5_context context, int loopcount; krb5_data salt; krb5_data s2kparams; - krb5_keyblock as_key; - krb5_keyblock *fast_as_key = NULL; + krb5_keyblock as_key, encrypting_key; + krb5_keyblock *strengthen_key = NULL; krb5_error *err_reply; krb5_kdc_rep *local_as_reply; krb5_timestamp time_now; @@ -994,6 +994,8 @@ krb5_get_init_creds(krb5_context context, preauth_to_use = NULL; kdc_padata = NULL; as_key.length = 0; + encrypting_key.length = 0; + encrypting_key.contents = NULL; salt.length = 0; salt.data = NULL; @@ -1340,8 +1342,6 @@ krb5_get_init_creds(krb5_context context, out_padata = NULL; krb5_free_error(context, err_reply); err_reply = NULL; - if (ret) - goto cleanup; ret = sort_krb5_padata_sequence(context, &request.server->realm, preauth_to_use); @@ -1399,7 +1399,7 @@ krb5_get_init_creds(krb5_context context, /* process any preauth data in the as_reply */ krb5_clear_preauth_context_use_counts(context); ret = krb5int_fast_process_response(context, fast_state, - local_as_reply, &fast_as_key); + local_as_reply, &strengthen_key); if (ret) goto cleanup; if ((ret = sort_krb5_padata_sequence(context, &request.server->realm, @@ -1447,18 +1447,15 @@ krb5_get_init_creds(krb5_context context, it. If decrypting the as_rep fails, or if there isn't an as_key at all yet, then use the gak_fct to get one, and try again. */ - if (fast_as_key) { - if (as_key.length) - krb5_free_keyblock_contents(context, &as_key); - as_key = *fast_as_key; - free(fast_as_key); - fast_as_key = NULL; - } - if (as_key.length) - ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, - NULL, &as_key, krb5_kdc_rep_decrypt_proc, + if (as_key.length) { + ret = krb5int_fast_reply_key(context, strengthen_key, &as_key, + &encrypting_key); + if (ret) + goto cleanup; + ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, + NULL, &encrypting_key, krb5_kdc_rep_decrypt_proc, NULL); - else + } else ret = -1; if (ret) { @@ -1470,6 +1467,10 @@ krb5_get_init_creds(krb5_context context, &as_key, gak_data)))) goto cleanup; + ret = krb5int_fast_reply_key(context, strengthen_key, &as_key, + &encrypting_key); + if (ret) + goto cleanup; if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, NULL, &as_key, krb5_kdc_rep_decrypt_proc, NULL))) @@ -1511,8 +1512,10 @@ cleanup: } } krb5_preauth_request_context_fini(context); - krb5_free_keyblock(context, fast_as_key); - if (fast_state) + krb5_free_keyblock(context, strengthen_key); + if (encrypting_key.contents) + krb5_free_keyblock_contents(context, &encrypting_key); + if (fast_state) krb5int_fast_free_state(context, fast_state); if (out_padata) krb5_free_pa_data(context, out_padata); diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c index d17d46bc7..bec9a61bf 100644 --- a/src/lib/krb5/krb/kfree.c +++ b/src/lib/krb5/krb/kfree.c @@ -819,6 +819,7 @@ void krb5_free_fast_response(krb5_context context, krb5_fast_response *val) return; krb5_free_pa_data(context, val->padata); krb5_free_fast_finished(context, val->finished); + krb5_free_keyblock(context, val->strengthen_key); free(val); } diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index 4c7dd5e60..73f4e79b6 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -645,6 +645,36 @@ krb5_error_code pa_salt(krb5_context context, return(0); } +static +krb5_error_code pa_fx_cookie(krb5_context context, + krb5_kdc_req *request, + krb5_pa_data *in_padata, + krb5_pa_data **out_padata, + krb5_data *salt, + krb5_data *s2kparams, + krb5_enctype *etype, + krb5_keyblock *as_key, + krb5_prompter_fct prompter, + void *prompter_data, + krb5_gic_get_as_key_fct gak_fct, + void *gak_data) +{ + krb5_pa_data *pa = calloc(1, sizeof(krb5_pa_data)); + krb5_octet *contents; + if (pa == NULL) + return ENOMEM; + contents = malloc(in_padata->length); + if (contents == NULL) { + free(pa); + return ENOMEM; + } + *pa = *in_padata; + pa->contents = contents; + memcpy(contents, in_padata->contents, pa->length); + *out_padata = pa; + return 0; +} + static krb5_error_code pa_enc_timestamp(krb5_context context, krb5_kdc_req *request, @@ -1709,6 +1739,11 @@ static const pa_types_t pa_types[] = { pa_sam, PA_REAL, }, + { + KRB5_PADATA_FX_COOKIE, + pa_fx_cookie, + PA_INFO, + }, { -1, NULL, diff --git a/src/lib/krb5/krb/t_ad_fx_armor.c b/src/lib/krb5/krb/t_ad_fx_armor.c new file mode 100644 index 000000000..74d7e5f1a --- /dev/null +++ b/src/lib/krb5/krb/t_ad_fx_armor.c @@ -0,0 +1,36 @@ +#include +#include +#include + +#define test(x) do {retval = (x); \ + if(retval != 0) { \ + const char *errmsg = krb5_get_error_message(context, retval); \ + fprintf(stderr, "Error message: %s\n", errmsg); \ + abort(); } \ + } while(0); + +krb5_authdata ad_fx_armor = {0, KRB5_AUTHDATA_FX_ARMOR, 1, ""}; +krb5_authdata *array[] = {&ad_fx_armor, NULL}; + + +int main( int argc, char **argv) +{ + krb5_context context; + krb5_ccache ccache = NULL; + krb5_creds creds, *out_creds = NULL; + krb5_error_code retval = 0; + test(krb5_init_context(&context)); + memset(&creds, 0, sizeof(creds)); + creds.authdata = array; + test(krb5_cc_default(context, &ccache)); + test(krb5_cc_get_principal(context, ccache, &creds.client)); + test(krb5_parse_name(context, argv[1], &creds.server)); + test(krb5_get_credentials(context, 0, ccache, &creds, &out_creds)); + test(krb5_cc_destroy(context, ccache)); + test(krb5_cc_default(context, &ccache)); + test(krb5_cc_initialize(context, ccache, out_creds->client)); + test(krb5_cc_store_cred(context, ccache, out_creds)); + test(krb5_cc_close(context,ccache)); + return 0; + +} diff --git a/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c index 3fad7ccd3..692449150 100644 --- a/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c +++ b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c @@ -116,6 +116,7 @@ static krb5_error_code process_preauth krb5_pa_data **pa_array = NULL; krb5_data *encoded_ts = NULL; krb5_pa_enc_ts ts; + enc.ciphertext.data = NULL; if (retval == 0) retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) @@ -300,8 +301,6 @@ static krb5_error_code kdc_verify_preauth } if (armor_key) krb5_free_keyblock(context, armor_key); - if (challenge_key) - krb5_free_keyblock(context, challenge_key); if (plain.data) free(plain.data); if (enc)