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