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

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



I have made significant changes to the text and it's pretty short so
I'll just inline the whole thing again. Thanks for your feedback.

Mike

--8<--

The Kerberos Keytab Binary File Format
Michael B Allen <mba2000 ioplex.com>
Last updated: Wed May  3 12:56:26 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.

  keytab {
      uint16_t file_format_version;
      keytab_entry entries[*];
  };

  struct keytab_entry {
      int32_t size;
      uint16_t num_components;
      counted_octet_string components[num_components - 1];
      uint32_t name_type;
      uint32_t timestamp;
      uint8_t vno8;
      keyblock key;
      uint32_t vno;
  };

  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 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 UTF-8 encoded text (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 bytes remaining, a 32 bit value
representing the key version number is present. This value superceeds
the 8 bit value preceeding the keyblock.