aboutsummaryrefslogtreecommitdiff
path: root/lib/hdb/keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hdb/keys.c')
-rw-r--r--lib/hdb/keys.c208
1 files changed, 119 insertions, 89 deletions
diff --git a/lib/hdb/keys.c b/lib/hdb/keys.c
index 96c221ed275e..457e5daf7a7b 100644
--- a/lib/hdb/keys.c
+++ b/lib/hdb/keys.c
@@ -31,21 +31,10 @@
* SUCH DAMAGE.
*/
+#include "krb5_locl.h"
#include "hdb_locl.h"
-struct hx509_certs_data;
-struct krb5_pk_identity;
-struct krb5_pk_cert;
-struct ContentInfo;
-struct AlgorithmIdentifier;
-struct _krb5_krb_auth_data;
-typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx;
-struct krb5_dh_moduli;
-struct _krb5_key_data;
-struct _krb5_encryption_type;
-struct _krb5_key_type;
#include <pkinit_asn1.h>
-#include <krb5-private.h>
#include <base64.h>
/*
@@ -212,18 +201,30 @@ parse_key_set(krb5_context context, const char *key,
}
/**
- * This function prunes an HDB entry's keys that are too old to have been used
- * to mint still valid tickets (based on the entry's maximum ticket lifetime).
- *
+ * This function prunes an HDB entry's historic keys by kvno.
+ *
* @param context Context
* @param entry HDB entry
+ * @param kvno Keyset kvno to prune, or zero to prune all too-old keys
*/
krb5_error_code
-hdb_prune_keys(krb5_context context, hdb_entry *entry)
+hdb_prune_keys_kvno(krb5_context context, hdb_entry *entry, int kvno)
{
HDB_extension *ext;
HDB_Ext_KeySet *keys;
+ hdb_keyset *elem;
+ time_t keep_time = 0;
size_t nelem;
+ size_t i;
+
+ /*
+ * XXX Pruning old keys for namespace principals may not be desirable, but!
+ * as long as the `set_time's of the base keys for a namespace principal
+ * match the `epoch's of the corresponding KeyRotation periods, it will be
+ * perfectly acceptable to prune old [base] keys for namespace principals
+ * just as for any other principal. Therefore, we may not need to make any
+ * changes here w.r.t. namespace principals.
+ */
ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
if (ext == NULL)
@@ -231,14 +232,12 @@ hdb_prune_keys(krb5_context context, hdb_entry *entry)
keys = &ext->data.u.hist_keys;
nelem = keys->len;
- /* Optionally drop key history for keys older than now - max_life */
- if (entry->max_life != NULL && nelem > 0
- && krb5_config_get_bool_default(context, NULL, FALSE,
- "kadmin", "prune-key-history", NULL)) {
- hdb_keyset *elem;
+ /*
+ * Optionally drop key history for keys older than now - max_life, which is
+ * all the keys no longer needed to decrypt extant tickets.
+ */
+ if (kvno == 0 && entry->max_life != NULL && nelem > 0) {
time_t ceiling = time(NULL) - *entry->max_life;
- time_t keep_time = 0;
- size_t i;
/*
* Compute most recent key timestamp that predates the current time
@@ -250,94 +249,123 @@ hdb_prune_keys(krb5_context context, hdb_entry *entry)
&& (keep_time == 0 || *elem->set_time > keep_time))
keep_time = *elem->set_time;
}
+ }
- /* Drop obsolete entries */
- if (keep_time) {
- for (i = 0; i < nelem; /* see below */) {
- elem = &keys->val[i];
- if (elem->set_time && *elem->set_time < keep_time) {
- remove_HDB_Ext_KeySet(keys, i);
- /*
- * Removing the i'th element shifts the tail down, continue
- * at same index with reduced upper bound.
- */
- --nelem;
- continue;
- }
- ++i;
- }
- }
+ if (kvno == 0 && keep_time == 0)
+ return 0;
+
+ for (i = 0; i < nelem; /* see below */) {
+ elem = &keys->val[i];
+ if ((kvno && kvno == elem->kvno) ||
+ (keep_time && elem->set_time && *elem->set_time < keep_time)) {
+ remove_HDB_Ext_KeySet(keys, i);
+ /*
+ * Removing the i'th element shifts the tail down, continue
+ * at same index with reduced upper bound.
+ */
+ --nelem;
+ continue;
+ }
+ ++i;
}
return 0;
}
/**
+ * This function prunes an HDB entry's keys that are too old to have been used
+ * to mint still valid tickets (based on the entry's maximum ticket lifetime).
+ *
+ * @param context Context
+ * @param entry HDB entry
+ */
+krb5_error_code
+hdb_prune_keys(krb5_context context, hdb_entry *entry)
+{
+ if (!krb5_config_get_bool_default(context, NULL, FALSE,
+ "kadmin", "prune-key-history", NULL))
+ return 0;
+ return hdb_prune_keys_kvno(context, entry, 0);
+}
+
+/**
+ * This function adds a keyset to an HDB entry's key history.
+ *
+ * @param context Context
+ * @param entry HDB entry
+ * @param kvno Key version number of the key to add to the history
+ * @param key The Key to add
+ */
+krb5_error_code
+hdb_add_history_keyset(krb5_context context,
+ hdb_entry *entry,
+ const hdb_keyset *ks)
+{
+ size_t i;
+ HDB_Ext_KeySet *hist_keys;
+ HDB_extension ext;
+ HDB_extension *extp;
+ krb5_error_code ret = 0;
+
+ memset(&ext, 0, sizeof (ext));
+
+ extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
+ if (extp == NULL) {
+ ext.mandatory = FALSE;
+ ext.data.element = choice_HDB_extension_data_hist_keys;
+ ext.data.u.hist_keys.len = 0;
+ ext.data.u.hist_keys.val = 0;
+ extp = &ext;
+ }
+ hist_keys = &extp->data.u.hist_keys;
+
+ for (i = 0; i < hist_keys->len; i++) {
+ if (hist_keys->val[i].kvno == ks->kvno) {
+ /* Replace existing */
+ free_HDB_keyset(&hist_keys->val[i]);
+ ret = copy_HDB_keyset(ks, &hist_keys->val[i]);
+ break;
+ }
+ }
+ if (i >= hist_keys->len)
+ ret = add_HDB_Ext_KeySet(hist_keys, ks); /* Append new */
+ if (ret == 0 && extp == &ext)
+ ret = hdb_replace_extension(context, entry, &ext);
+ free_HDB_extension(&ext);
+ return ret;
+}
+
+/**
* This function adds an HDB entry's current keyset to the entry's key
* history. The current keyset is left alone; the caller is responsible
* for freeing it.
*
* @param context Context
* @param entry HDB entry
+ *
+ * @return Zero on success, or an error code otherwise.
*/
krb5_error_code
hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry)
{
- krb5_boolean replace = FALSE;
krb5_error_code ret;
- HDB_extension *ext;
- HDB_Ext_KeySet *keys;
- hdb_keyset newkeyset;
+ hdb_keyset ks;
time_t newtime;
if (entry->keys.len == 0)
return 0; /* nothing to do */
- ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
- if (ext == NULL) {
- replace = TRUE;
- ext = calloc(1, sizeof (*ext));
- if (ext == NULL)
- return krb5_enomem(context);
-
- ext->data.element = choice_HDB_extension_data_hist_keys;
- }
- keys = &ext->data.u.hist_keys;
-
- ext->mandatory = FALSE;
-
- /*
- * Copy in newest old keyset
- */
ret = hdb_entry_get_pw_change_time(entry, &newtime);
if (ret)
- goto out;
-
- memset(&newkeyset, 0, sizeof(newkeyset));
- newkeyset.keys = entry->keys;
- newkeyset.kvno = entry->kvno;
- newkeyset.set_time = &newtime;
-
- ret = add_HDB_Ext_KeySet(keys, &newkeyset);
- if (ret)
- goto out;
-
- if (replace) {
- /* hdb_replace_extension() deep-copies ext; what a waste */
- ret = hdb_replace_extension(context, entry, ext);
- if (ret)
- goto out;
- }
+ return ret;
- ret = hdb_prune_keys(context, entry);
- if (ret)
- goto out;
+ ks.keys = entry->keys;
+ ks.kvno = entry->kvno;
+ ks.set_time = &newtime;
- out:
- if (replace && ext) {
- free_HDB_extension(ext);
- free(ext);
- }
+ ret = hdb_add_history_keyset(context, entry, &ks);
+ if (ret == 0)
+ ret = hdb_prune_keys(context, entry);
return ret;
}
@@ -348,6 +376,8 @@ hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry)
* @param entry HDB entry
* @param kvno Key version number of the key to add to the history
* @param key The Key to add
+ *
+ * @return Zero on success, or an error code otherwise.
*/
krb5_error_code
hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key)
@@ -392,12 +422,11 @@ hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key
}
out:
- free_hdb_keyset(&keyset);
+ free_HDB_keyset(&keyset);
free_HDB_extension(&ext);
return ret;
}
-
/**
* This function changes an hdb_entry's kvno, swapping the current key
* set with a historical keyset. If no historical keys are found then
@@ -433,7 +462,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
for (i = 0; i < hist_keys->len; i++) {
if (hist_keys->val[i].kvno == new_kvno) {
found = 1;
- ret = copy_hdb_keyset(&hist_keys->val[i], &keyset);
+ ret = copy_HDB_keyset(&hist_keys->val[i], &keyset);
if (ret)
goto out;
ret = remove_HDB_Ext_KeySet(hist_keys, i);
@@ -456,7 +485,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
memset(&keyset.keys, 0, sizeof (keyset.keys));
out:
- free_hdb_keyset(&keyset);
+ free_HDB_keyset(&keyset);
return ret;
}
@@ -654,7 +683,8 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal,
ktypes = ks_tuple_strs;
if (ktypes == NULL) {
- ktypes = glob_rules_keys(context, principal);
+ config_ktypes = glob_rules_keys(context, principal);
+ ktypes = config_ktypes;
}
if (ktypes == NULL) {
config_ktypes = krb5_config_get_strings(context, NULL, "kadmin",