From 678f9f9f070134f62b49b833b2f5364c660a530f Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 11 Oct 2009 08:46:53 -0700 Subject: [PATCH] [HEIMDAL-533] KDC sends TGS-REP encrypted in session key not authenticator From RFC 4120, page 35 In preparing the authentication header, the client can select a sub- session key under which the response from the Kerberos server will be encrypted. If the client selects a sub-session key, care must be taken to ensure the randomness of the selected sub-session key. The client library alread handle this case. Thanks to Sam Hartman to report this though Debian --- kdc/kerberos5.c | 5 +-- kdc/krb5tgs.c | 81 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 0a9d4a5ca..67c7a10c7 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -261,6 +261,7 @@ _kdc_encode_reply(krb5_context context, krb5_enctype etype, int skvno, const EncryptionKey *skey, int ckvno, const EncryptionKey *reply_key, + int rk_is_subkey, const char **e_text, krb5_data *reply) { @@ -341,7 +342,7 @@ _kdc_encode_reply(krb5_context context, } else { krb5_encrypt_EncryptedData(context, crypto, - KRB5_KU_TGS_REP_ENC_PART_SESSION, + rk_is_subkey ? KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : KRB5_KU_TGS_REP_ENC_PART_SESSION, buf, len, ckvno, @@ -1757,7 +1758,7 @@ _kdc_as_rep(krb5_context context, ret = _kdc_encode_reply(context, config, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, - reply_key, &e_text, reply); + reply_key, 0, &e_text, reply); free_EncTicketPart(&et); free_EncKDCRepPart(&ek); if (ret) diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 34ecabf56..6371f9305 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -671,6 +671,8 @@ tgs_make_reply(krb5_context context, KDC_REQ_BODY *b, krb5_const_principal tgt_name, const EncTicketPart *tgt, + const krb5_keyblock *replykey, + int rk_is_subkey, const EncryptionKey *serverkey, const krb5_keyblock *sessionkey, krb5_kvno kvno, @@ -931,7 +933,8 @@ tgs_make_reply(krb5_context context, ret = _kdc_encode_reply(context, config, &rep, &et, &ek, et.key.keytype, kvno, - serverkey, 0, &tgt->key, e_text, reply); + serverkey, 0, replykey, rk_is_subkey, + e_text, reply); if (is_weak) krb5_enctype_disable(context, et.key.keytype); @@ -1081,7 +1084,9 @@ tgs_parse_request(krb5_context context, const struct sockaddr *from_addr, time_t **csec, int **cusec, - AuthorizationData **auth_data) + AuthorizationData **auth_data, + krb5_keyblock **replykey, + int *rk_is_subkey) { krb5_ap_req ap_req; krb5_error_code ret; @@ -1091,10 +1096,13 @@ tgs_parse_request(krb5_context context, krb5_flags verify_ap_req_flags; krb5_crypto crypto; Key *tkey; + krb5_keyblock *subkey = NULL; + unsigned usage; *auth_data = NULL; *csec = NULL; *cusec = NULL; + *replykey = NULL; memset(&ap_req, 0, sizeof(ap_req)); ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); @@ -1223,37 +1231,42 @@ tgs_parse_request(krb5_context context, goto out; } - if (b->enc_authorization_data) { - unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; - krb5_keyblock *subkey; - krb5_data ad; + usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; + *rk_is_subkey = 1; - ret = krb5_auth_con_getremotesubkey(context, ac, &subkey); - if(ret){ + ret = krb5_auth_con_getremotesubkey(context, ac, &subkey); + if(ret){ + krb5_auth_con_free(context, ac); + kdc_log(context, config, 0, "Failed to get remote subkey: %s", + krb5_get_err_text(context, ret)); + goto out; + } + if(subkey == NULL){ + usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; + *rk_is_subkey = 0; + + ret = krb5_auth_con_getkey(context, ac, &subkey); + if(ret) { krb5_auth_con_free(context, ac); - kdc_log(context, config, 0, "Failed to get remote subkey: %s", + kdc_log(context, config, 0, "Failed to get session key: %s", krb5_get_err_text(context, ret)); goto out; } - if(subkey == NULL){ - usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; - ret = krb5_auth_con_getkey(context, ac, &subkey); - if(ret) { - krb5_auth_con_free(context, ac); - kdc_log(context, config, 0, "Failed to get session key: %s", - krb5_get_err_text(context, ret)); - goto out; - } - } - if(subkey == NULL){ - krb5_auth_con_free(context, ac); - kdc_log(context, config, 0, - "Failed to get key for enc-authorization-data"); - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ - goto out; - } + } + if(subkey == NULL){ + krb5_auth_con_free(context, ac); + kdc_log(context, config, 0, + "Failed to get key for enc-authorization-data"); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ + goto out; + } + + *replykey = subkey; + + if (b->enc_authorization_data) { + krb5_data ad; + ret = krb5_crypto_init(context, subkey, 0, &crypto); - krb5_free_keyblock(context, subkey); if (ret) { krb5_auth_con_free(context, ac); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", @@ -1381,6 +1394,8 @@ tgs_build_reply(krb5_context context, KDC_REQ_BODY *b, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, + const krb5_keyblock *replykey, + int rk_is_subkey, krb5_ticket *ticket, krb5_data *reply, const char *from, @@ -1954,6 +1969,8 @@ server_lookup: b, client_principal, tgt, + replykey, + rk_is_subkey, ekey, &sessionkey, kvno, @@ -2020,6 +2037,8 @@ _kdc_tgs_rep(krb5_context context, const char *e_text = NULL; krb5_enctype krbtgt_etype = ETYPE_NULL; + krb5_keyblock *replykey = NULL; + int rk_is_subkey = 0; time_t *csec = NULL; int *cusec = NULL; @@ -2047,7 +2066,9 @@ _kdc_tgs_rep(krb5_context context, &e_text, from, from_addr, &csec, &cusec, - &auth_data); + &auth_data, + &replykey, + &rk_is_subkey); if (ret) { kdc_log(context, config, 0, "Failed parsing TGS-REQ from %s", from); @@ -2060,6 +2081,8 @@ _kdc_tgs_rep(krb5_context context, &req->req_body, krbtgt, krbtgt_etype, + replykey, + rk_is_subkey, ticket, data, from, @@ -2080,6 +2103,8 @@ _kdc_tgs_rep(krb5_context context, } out: + if (replykey) + krb5_free_keyblock(context, replykey); if(ret && data->data == NULL){ krb5_mk_error(context, ret,