Crypto Modularity proj proposal

Greg Hudson ghudson at MIT.EDU
Wed Jun 24 13:40:40 EDT 2009

The code organization part has already been discussed and I think is
mostly uncontroversial.

The hard part is what we do to allow keyblocks to support:
  * Caching of derived keys
  * Caching of implementation object handles for keys
  * References to keys stored opaquely in cryptographic modules
The second and third points are related; I'm just drawing a distinction
between the performance goal of not having to create an object handle
for each operation and the functionality goal of being able to support
opaque, external storage of long-term keys.

There is some previous discussion of this in the thread beginning at:


The basic options I am aware of are:

* Do nothing, and simply support none of the above-listed functionality.
This sacrifices much of the value of the crypto modularity project,
delivering only the ability to use different implementations of exactly
the same crypto functionality as we currently have, likely without much
opportunity for performance gains.

* Simply change the size of the keyblock structures, breaking
compatibility with the krb5 API and ABI.  It's important to recognize
that keyblock structures are contained by value inside krb5_creds and
krb5_keytab_entry structures, and by reference in a few other
structures.  Even if it's rare for application code to play with
krb5_keyblocks directly, any code which acquires and dereferences a
krb5_creds structure would also experience ABI breakage.

* Same as above, but use a configure switch to determine whether to
build with the old or new ABI/API.  This option effectively delegates
the pain of breakage to the OS, but does not mitigate it.  This option
has specific advantages for Sun if we use a specific set of new
structure fields.

* Rev every part of the API which deals with keyblocks.  By this I mean
create new structure and function names for every library symbol
affected by keyblocks, and make the old names operate in a compatibility
mode.  Because of the infiltration of keyblocks into credentials, this
is a pretty massive change.  Some of the higher-level functions might
remain untouched (like rd_req and mk_req), although at least mk_creds
and rd_creds would have to change.

* Reuse the contents field of a keyblock as a pointer to an extended
structure; this allows us to add fields without changing the size.
Label this using a new magic number, so that keyblocks constructed by
old application code would continue to work with lower efficiency.  This
is effectively breaking the ABI and API, but in a more limited way:
  - Code which retrieves a keyblock and directly uses the contents would
break ungracefully (probably seg faulting); affected code might include
things like aklog which push keys from user space into kernel space.
  - Because we do not check magic numbers in every function currently
using keyblocks, old code does not necessarily set these fields.  It's
unlikely for random stack or heap garbage to contain the new magic
number--but stack garbage is not random, and it's quite conceivable for
the new magic number to make its way from a deallocated or discarded
keyblock structure to the uninitialized magic field of an
application-created keyblock.  We can mitigate this possibility somewhat
by zeroing the magic field in krb5int_c_free_keyblock_contents.

* Same as above, but using a special enctype instead of a new magic
number.  This option sidesteps the uninitialized-magic problem, but has
different pitfalls in the other department:
  - Code which retrieves a keyblock and directly uses the contents has
at least a chance of breaking more gracefully, as it might check the
enctype first.  But it might still fail ungracefully.
  - Code which retrieves a keyblock and examines the enctype (but does
not directly use the contents) will fail, when it would have succeeded
under the new-magic-number option.

* In the krb5_context, store a lookaside table mapping keyblock contents
to extended structures.  This structure would be somewhat slow to access
because of the need to hash and maybe compare 128-bit or 256-bit values.
In some cases the extended structures might not be found:
  - If it never existed (keyblock constructed by application code)
  - If a keyblock is used with a different krb5_context from the one it
was created in
  - If a keyblock is copied, and then the original freed (triggering the
removal of the lookaside entry)
Failure to find extended structures would only impact performance,
except when opaque external key references are used.

* Same as the above option, but use keyblock addresses instead of
contents as the keys for better performance.  Nico considered this
option in September but discarded it because keyblocks can be
stack-allocated; I am not sure if that's a fatal objection.  If we only
create lookaside entries at keyblock construction time, we can avoid
creating entries for stack-allocated keyblocks (or, more generally,
keyblocks that won't be freed through an API we control); the downside
is that we don't cache derived keys or object handles for
application-constructed keyblocks unless they use some new constructor

I'm interested in discussion of which option is best, and options we
might have missed.  Please keep the conversation forward-looking; we are
not currently budgeted for a time machine.

On Thu, 2009-06-18 at 14:40 -0400, Zhanna Tsitkova wrote:
> A new project proposal is posted on 
>    to address Crypto Modularity of MIT Kerberos code.
> _______________________________________________
> krbdev mailing list             krbdev at

More information about the krbdev mailing list