From: Greg Hudson Date: Wed, 13 May 2020 17:01:31 +0000 (-0400) Subject: Add KDC helpers for current key and kvno X-Git-Tag: krb5-1.19-beta1~81 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42e21c57261f78cf0c68cbef16d58ca4a106f0e0;p=thirdparty%2Fkrb5.git Add KDC helpers for current key and kvno Add a simple static inline function current_kvno() to safely fetch the current kvno of a principal entry, and use it where we currently write entry->key_data[0].key_data_kvno. Add a function get_first_current_key() to find and decrypt the first valid current key from an entry. Use it in get_local_tgt() and when selecting a ticket encryption key during AS and TGS processing. Add a local_tgt_key field to krb5_kdcpreauth_rock_st and use it in add_freshness_token() so we don't have to decrypt it again. --- diff --git a/src/kdc/cammac.c b/src/kdc/cammac.c index 9837463c40..df5fe966f2 100644 --- a/src/kdc/cammac.c +++ b/src/kdc/cammac.c @@ -80,7 +80,7 @@ cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt, if (ret) goto cleanup; kdc_verifier.princ = NULL; - kdc_verifier.kvno = tgt->key_data[0].key_data_kvno; + kdc_verifier.kvno = current_kvno(tgt); kdc_verifier.enctype = ENCTYPE_NULL; kdc_verifier.checksum = kdc_cksum; @@ -149,7 +149,7 @@ cammac_check_kdcver(krb5_context context, krb5_cammac *cammac, /* Fetch the krbtgt key indicated by the KDC verifier. Only allow the * first krbtgt key of the specified kvno. */ - if (ver->kvno == tgt->key_data[0].key_data_kvno) { + if (ver->kvno == current_kvno(tgt)) { key = tgt_key; } else { if (krb5_dbe_find_enctype(context, tgt, -1, -1, ver->kvno, &kd) != 0) diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 9ae7b0a5e8..a89301028a 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -192,7 +192,6 @@ struct as_req_state { static void finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) { - krb5_key_data *server_key; krb5_keyblock *as_encrypting_key = NULL; krb5_data *response = NULL; const char *emsg = 0; @@ -220,32 +219,13 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) if (errcode) goto egress; - /* - * Find the server key - */ - if ((errcode = krb5_dbe_find_enctype(kdc_context, state->server, - -1, /* ignore keytype */ - -1, /* Ignore salttype */ - 0, /* Get highest kvno */ - &server_key))) { + errcode = get_first_current_key(kdc_context, state->server, + &state->server_keyblock); + if (errcode) { state->status = "FINDING_SERVER_KEY"; goto egress; } - /* - * Convert server->key into a real key - * (it may be encrypted in the database) - * - * server_keyblock is later used to generate auth data signatures - */ - if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL, - server_key, - &state->server_keyblock, - NULL))) { - state->status = "DECRYPT_SERVER_KEY"; - goto egress; - } - /* Start assembling the response */ state->reply.msg_type = KRB5_AS_REP; state->reply.client = state->enc_tkt_reply.client; /* post canonization */ @@ -311,7 +291,7 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) if (errcode) goto egress; - state->ticket_reply.enc_part.kvno = server_key->key_data_kvno; + state->ticket_reply.enc_part.kvno = current_kvno(state->server); errcode = kdc_fast_response_handle_padata(state->rstate, state->request, &state->reply, @@ -659,6 +639,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, goto errout; } state->rock.local_tgt = state->local_tgt; + state->rock.local_tgt_key = &state->local_tgt_key; au_state->stage = VALIDATE_POL; diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index 463a9c0dd8..8860fe81f8 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -120,7 +120,6 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt, krb5_timestamp kdc_time, authtime = 0; krb5_keyblock session_key, local_tgt_key; krb5_keyblock *reply_key = NULL; - krb5_key_data *server_key; krb5_principal cprinc = NULL, sprinc = NULL, altcprinc = NULL; krb5_const_principal authdata_client; krb5_principal stkt_authdata_client = NULL; @@ -523,28 +522,11 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt, krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2; encrypting_key = t2enc->session; } else { - /* - * Find the server key - */ - if ((errcode = krb5_dbe_find_enctype(kdc_context, server, - -1, /* ignore keytype */ - -1, /* Ignore salttype */ - 0, /* Get highest kvno */ - &server_key))) { + errcode = get_first_current_key(kdc_context, server, &server_keyblock); + if (errcode) { status = "FINDING_SERVER_KEY"; goto cleanup; } - - /* - * Convert server.key into a real key - * (it may be encrypted in the database) - */ - if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL, - server_key, &server_keyblock, - NULL))) { - status = "DECRYPT_SERVER_KEY"; - goto cleanup; - } encrypting_key = &server_keyblock; } @@ -680,7 +662,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt, kau_u2u(kdc_context, TRUE, au_state); st_idx++; } else { - ticket_kvno = server_key->key_data_kvno; + ticket_kvno = current_kvno(server); } errcode = krb5_encrypt_tkt_part(kdc_context, encrypting_key, diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c index e4bb3cedbb..ff3338e407 100644 --- a/src/kdc/fast_util.c +++ b/src/kdc/fast_util.c @@ -508,7 +508,7 @@ get_cookie_key(krb5_context context, krb5_db_entry *tgt, *key_out = NULL; memset(&storage, 0, sizeof(storage)); - if (kvno == tgt->key_data[0].key_data_kvno) { + if (kvno == current_kvno(tgt)) { /* Use the already-decrypted first key. */ key = tgt_key; } else { @@ -711,7 +711,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state, ret = k5_alloc_pa_data(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa); memcpy(pa->contents, "MIT1", 4); - store_32_be(local_tgt->key_data[0].key_data_kvno, pa->contents + 4); + store_32_be(current_kvno(local_tgt), pa->contents + 4); memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length); *cookie_out = pa; diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 04cd0e7129..8d832743d2 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -811,7 +811,6 @@ add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock, { krb5_error_code ret; krb5_timestamp now; - krb5_key_data *kd; krb5_keyblock kb; krb5_checksum cksum; krb5_data d; @@ -827,29 +826,21 @@ add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock, KRB5_PADATA_AS_FRESHNESS) == NULL) return 0; - /* Fetch and decrypt the current local krbtgt key. */ - ret = krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, 0, &kd); - if (ret) - goto cleanup; - ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL); - if (ret) - goto cleanup; - /* Compute a checksum over the current KDC time. */ ret = krb5_timeofday(context, &now); if (ret) goto cleanup; store_32_be(now, ckbuf); d = make_data(ckbuf, sizeof(ckbuf)); - ret = krb5_c_make_checksum(context, 0, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS, - &d, &cksum); + ret = krb5_c_make_checksum(context, 0, rock->local_tgt_key, + KRB5_KEYUSAGE_PA_AS_FRESHNESS, &d, &cksum); /* Compose a freshness token from the time, krbtgt kvno, and checksum. */ ret = k5_alloc_pa_data(KRB5_PADATA_AS_FRESHNESS, 8 + cksum.length, &pa); if (ret) goto cleanup; store_32_be(now, pa->contents); - store_32_be(kd->key_data_kvno, pa->contents + 4); + store_32_be(current_kvno(rock->local_tgt), pa->contents + 4); memcpy(pa->contents + 8, cksum.contents, cksum.length); ret = k5_add_pa_data_element(pa_list, &pa); diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 4390b289d1..b3bca52b12 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -496,6 +496,22 @@ errout: return retval; } +/* Find the first key data entry (of a valid enctype) of the highest kvno in + * entry, and decrypt it into *key_out. */ +krb5_error_code +get_first_current_key(krb5_context context, krb5_db_entry *entry, + krb5_keyblock *key_out) +{ + krb5_error_code ret; + krb5_key_data *kd; + + memset(key_out, 0, sizeof(*key_out)); + ret = krb5_dbe_find_enctype(context, entry, -1, -1, 0, &kd); + if (ret) + return ret; + return krb5_dbe_decrypt_key_data(context, NULL, kd, key_out, NULL); +} + /* * If candidate is the local TGT for realm, set *alias_out to candidate and * *storage_out to NULL. Otherwise, load the local TGT into *storage_out and @@ -514,7 +530,6 @@ get_local_tgt(krb5_context context, const krb5_data *realm, krb5_error_code ret; krb5_principal princ; krb5_db_entry *storage = NULL, *tgt; - krb5_key_data *kd; *alias_out = NULL; *storage_out = NULL; @@ -535,11 +550,7 @@ get_local_tgt(krb5_context context, const krb5_data *realm, tgt = candidate; } - /* Find and decrypt the first valid key of the current kvno. */ - ret = krb5_dbe_find_enctype(context, tgt, -1, -1, 0, &kd); - if (ret) - goto cleanup; - ret = krb5_dbe_decrypt_key_data(context, NULL, kd, key_out, NULL); + ret = get_first_current_key(context, tgt, key_out); if (ret) goto cleanup; diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 0b087d2ad3..ff87cd647b 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -70,6 +70,10 @@ kdc_get_server_key (krb5_context, krb5_ticket *, unsigned int, krb5_boolean match_enctype, krb5_db_entry **, krb5_keyblock **, krb5_kvno *); +krb5_error_code +get_first_current_key(krb5_context context, krb5_db_entry *entry, + krb5_keyblock *key_out); + krb5_error_code get_local_tgt(krb5_context context, const krb5_data *realm, krb5_db_entry *candidate, krb5_db_entry **alias_out, @@ -421,6 +425,7 @@ struct krb5_kdcpreauth_rock_st { krb5_data *inner_body; krb5_db_entry *client; krb5_db_entry *local_tgt; + krb5_keyblock *local_tgt_key; krb5_key_data *client_key; krb5_keyblock *client_keyblock; struct kdc_request_state *rstate; @@ -526,4 +531,11 @@ int errcode_to_protocol(krb5_error_code code); char *data2string(krb5_data *d); +/* Return the current key version of entry, or 0 if it has no keys. */ +static inline krb5_kvno +current_kvno(krb5_db_entry *entry) +{ + return (entry->n_key_data == 0) ? 0 : entry->key_data[0].key_data_kvno; +} + #endif /* __KRB5_KDC_UTIL__ */