History key changeover in depth
ghudson at MIT.EDU
Fri Feb 5 12:30:31 EST 2010
Here is the current state of our history key code:
* The libkadm5 operations chpass, randkey, setkey, and setv4key refuse
to work on the kadmin/history principal, so there is no UI for
changing the history key.
* When we initialize the database, we decrypt and remember the first
history key entry (hist_key); we also store its kvno (hist_kvno) and
the principal DB entry (hist_db), although we never actually use
that last. hist_kvno is always 2 in normal operation, because the
history DB entry gets created using the old create-and-randomize
* When we create a principal, we populate its admin-specific fields
with the hist_kvno (again, always 2 if nothing was done under the
covers) in the admin_history_kvno field.
* When we change or randomize a principal's password, we error out if
the principal's admin_history_kvno field doesn't match the
remembered history kvno from initialization. So even if there were
a UI for changing the history key, it would break password changes
for principals with policies. (As an aside, it seems weird to do
password history stuff in randkey, especially when we don't do it
Previously, I stated that we planned to allow gimpy history key
migration for 1.8--that is, you can change the key and ditch your
password history--and in the long term, migrate to using the master
key to encrypt password entries, so that the admin doesn't have to
worry about an extra key entry (and so that we don't have to worry
about having a good UI for migrating it). There are some design
complications to that plan; kdb5_util update_princ_encryption would
need to update password history entries in addition to key data, and
kdb5_util purge_mkeys would have to check history entries to see what
master keys are used.
Here are the little design issues associated with gimpy history key
* randkey_principal needs to allow changing of the history key. I
think it should truncate the key/salt list to one entry when it does
* If you randomize the history key, the existing kadmind or
kadmin.local process needs to update its remembered history key
globals. Other running processes could also wind up with stale
remembered globals (e.g. if you make the change in kadmin.local and
there is a running kadmind), and we need some kind of trigger to
update them. I'm not yet sure what this trigger should be, or if we
should just document that all kadminds must be restarted to
guarantee use of the new history key.
* When we change a password, we need to tolerate the
admin_history_kvno being different from the remembered hist_kvno.
If it's higher, we need to refresh our globals and try again. (This
is not a comprehensive trigger point for updating stale global
information, since we might only wind up operating on non-updated
principals for an extended period of time.) If it's lower, then we
need to discard the principal's password history, update the
admin_history_kvno field, and start a new history. Or we could keep
the old history entries and just let them fail to decrypt, but that
It might not be that much harder to implement a form of real history
key rollover for 1.8, although it would be redundant work if we
eventually migrate to master keys. To do that would involve a
slightly different set of design issues:
* The global history state could retain its current structure,
although we'd have to decrypt and remember the most recent key
rather than the first one. Other history keys could be decrypted as
needed. Alternatively, we could store a whole list of decrypted
history keys like we do for master keys.
* randkey_principal would need to allow changing of the history key,
but would have to force keeping the old entries. As above, I think
truncating the key/salt list to one entry would be wise.
* As above, the global remembered history key information would become
stale when the history key is changed, and we would need some kind
of trigger to update it.
* When change a password, if the principal's admin_history_kvno is
lower than the current max value, we need to re-encrypt the existing
password history (using the older keys in the history db entry to
decrypt them) in the newest history key and update the
It's mostly the same set of code changes, except that there is
probably more code to write for updating old password histories.
More information about the krbdev