krb5 commit: Add KDC helpers for current key and kvno
Greg Hudson
ghudson at mit.edu
Fri May 15 19:10:45 EDT 2020
https://github.com/krb5/krb5/commit/42e21c57261f78cf0c68cbef16d58ca4a106f0e0
commit 42e21c57261f78cf0c68cbef16d58ca4a106f0e0
Author: Greg Hudson <ghudson at mit.edu>
Date: Wed May 13 13:01:31 2020 -0400
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.
src/kdc/cammac.c | 4 ++--
src/kdc/do_as_req.c | 29 +++++------------------------
src/kdc/do_tgs_req.c | 24 +++---------------------
src/kdc/fast_util.c | 4 ++--
src/kdc/kdc_preauth.c | 15 +++------------
src/kdc/kdc_util.c | 23 +++++++++++++++++------
src/kdc/kdc_util.h | 12 ++++++++++++
7 files changed, 44 insertions(+), 67 deletions(-)
diff --git a/src/kdc/cammac.c b/src/kdc/cammac.c
index 9837463..df5fe96 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 9ae7b0a..a893010 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 463a9c0..8860fe8 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 e4bb3ce..ff3338e 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 04cd0e7..8d83274 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 4390b28..b3bca52 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 0b087d2..ff87cd6 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -71,6 +71,10 @@ kdc_get_server_key (krb5_context, krb5_ticket *, unsigned int,
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,
krb5_db_entry **storage_out, krb5_keyblock *kb_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__ */
More information about the cvs-krb5
mailing list