History key changeover in depth

ghudson@MIT.EDU 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
  in setkey.)

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
  seems pointless.

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
  admin_history_kvno field.

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 mailing list