[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: keytab - MIT Keytab Binary File Format Encoder / Decoder



On Wed, 03 May 2006 21:51:27 +0200
Love Hörnquist Åstrand <lha@kth.se> wrote:

> >   counted_octet_string {
> 
> The "principal" part uses int32 lengths for the strings (int16 for
> num_components) while the keyblock uses int16 lengths.
> 
> >       uint16_t length; 
> >       uint8_t data[length];
> >   };

My C-like notation is used only to describe the binary file format and not
an internal representation. In keytabs that I have looked at, the lengths
for strings are 16 bit and unless there is some significance to a negative
value (e.g. entry size) I think all integers should be shown unsigned.

By "version 1" I suppose you mean the file_format_version field would
be 0x501? At least from looking at the heimdal code it interprets
a 1 in that second byte to mean "version 1" but it's not clear how
the major version number is interpreted. Regarding version 1 keytabs,
can you verify that the comments in the keytab_entry structure and the
description of version 0x501 keytabs in the last paragraph are correct?

Also, from looking at the Heimdal code, I've noticed that the 32 bit
kvno field is only decoded if there are exactly 4 bytes left. Should
that not be >= 4 bytes in anticipation of further expansion?

Thanks for your feedback. You're welcome to use the text (or modify it
however you like) in your documentation although I would appreciate an
attribution if you keep track of such things.

Mike

--8<--

The Kerberos Keytab Binary File Format
Michael B Allen <mba2000 ioplex.com>
Last updated: Thu May  4 13:16:23 EDT 2006

The MIT keytab binary format is not a standard format, nor is it
documentated anywhere in detail. The format has evolved and may continue
to. It is however understood by several Kerberos implementations including
Heimdal and of course MIT and keytab files are created by the ktpass.exe
utility from Windows. So it has established itself as the defacto format
for storing Kerberos keys.

The following C-like structure definitions illustrate the MIT keytab
file format. All values are in network byte order. All text is ASCII.

  keytab {
      uint16_t file_format_version;                    /* 0x502 */
      keytab_entry entries[*];
  };

  keytab_entry {
      int32_t size;
      uint16_t num_components;   /* subtract 1 if version 0x501 */
      counted_octet_string realm;
      counted_octet_string components[num_components];
      uint32_t name_type;       /* not present if version 0x501 */
      uint32_t timestamp;
      uint8_t vno8;
      keyblock key;
      uint32_t vno; /* only present if >= 4 bytes left in entry */
  };

  counted_octet_string {
      uint16_t length;
      uint8_t data[length];
  };

  keyblock {
      uint16_t type;
      counted_octet_string;
  };

The keytab file format begins with the 16 bit file_format_version which
at the time this document was authored is 0x502. The format of older
keytabs is described at the end of this document.

The file_format_version is immediately followed by an array of
keytab_entry structures which are prefixed with a 32 bit size indicating
the number of bytes that follow in the entry. Note that the size should be
evaluated as signed. This is because a negative value indicates that the
entry is in fact empty (e.g. it has been deleted) and that the negative
value of that negative value (which is of course a positive value) is
the offset to the next keytab_entry. Based on these size values alone
the entire keytab file can be traversed.

The size is followed by a 16 bit num_components field indicating the
number of counted_octet_string components *minus one* that constitute
the name. A counted_octet_string is simply an array of bytes prefixed
with a 16 bit length. For the name components, the counted_octet_string
bytes are ASCII encoded text with no zero terminator.

Following the components array is the 32 bit name_type (e.g. 1 is
KRB5_NT_PRINCIPAL, 2 is KRB5_NT_SRV_INST, 5 is KRB5_NT_UID, etc).

In practice the name_type is almost certainly 1 meaning
KRB5_NT_PRINCIPAL. For this type of entry the components array consists
of the realm, service and name (in that order) although if num_components
is 1, the service component is not present. For example, the service
principal HTTP/quark.foo.net@FOO.NET would be encoded with name components
"FOO.NET" followed by "HTTP" followed by "quark.foo.net".

The 32 bit timestamp indicates the time the key was established for that
principal. The value represents the number of seconds since Jan 1, 1970.

The 8 bit vno8 field is the version number of the key. This value is
overridden by the vno field if it is present.

The keyblock structure consists of a 16 bit value indicating the keytype
(e.g. 3 is des-cbc-md5, 23 is arcfour-hmac-md5, 16 is des3-cbc-sha1,
etc). This is followed by a counted_octet_string containing the key.

The last field of the keytab_entry structure is optional. If the size of
the keytab_entry indicates that there are at least 4 bytes remaining,
a 32 bit value representing the key version number is present. This
value superceeds the 8 bit value preceeding the keyblock.

Keytabs with a file_format_version of 0x501 are different in three ways:

  1) All integers are in host byte order [1].
  2) The num_components field is 1 too large (i.e. fter decoding,
     decrement by 1).
  3) The 32 bit name_type field is not present.

[1] The file_format_version field should really be treated as two
    separate 8 bit quantities representing the major and minor version
    number respectively.