This is heimdal.info, produced by makeinfo version 4.0 from
heimdal.texi.

INFO-DIR-SECTION Security
START-INFO-DIR-ENTRY
* Heimdal: (heimdal).           The Kerberos 5 distribution from KTH
END-INFO-DIR-ENTRY


File: heimdal.info,  Node: Walkthrough of a sample Kerberos 5 client,  Next: Validating a password in a server application,  Prev: Kerberos 5 API Overview,  Up: Programming with Kerberos

Walkthrough of a sample Kerberos 5 client
=========================================

This example contains parts of a sample TCP Kerberos 5 clients, if you
want a real working client, please look in `appl/test' directory in the
Heimdal distribution.

All Kerberos error-codes that are returned from kerberos functions in
this program are passed to `krb5_err', that will print a descriptive
text of the error code and exit. Graphical programs can convert
error-code to a human readable error-string with the
`krb5_get_err_text(3)' function.

Note that you should not use any Kerberos function before
`krb5_init_context()' have completed successfully. That is the reason
`err()' is used when `krb5_init_context()' fails.

First the client needs to call `krb5_init_context' to initialise the
Kerberos 5 library. This is only needed once per thread in the program.
If the function returns a non-zero value it indicates that either the
Kerberos implementation is failing or its disabled on this host.

     #include <krb5.h>
     
     int
     main(int argc, char **argv)
     {
             krb5_context context;
     
             if (krb5_context(&context))
                     errx (1, "krb5_context");

Now the client wants to connect to the host at the other end. The
preferred way of doing this is using `getaddrinfo(3)' (for operating
system that have this function implemented), since getaddrinfo is
neutral to the address type and can use any protocol that is available.

             struct addrinfo *ai, *a;
             struct addrinfo hints;
             int error;
     
             memset (&hints, 0, sizeof(hints));
             hints.ai_socktype = SOCK_STREAM;
             hints.ai_protocol = IPPROTO_TCP;
     
             error = getaddrinfo (hostname, "pop3", &hints, &ai);
             if (error)
                     errx (1, "%s: %s", hostname, gai_strerror(error));
     
             for (a = ai; a != NULL; a = a->ai_next) {
                     int s;
     
                     s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
                     if (s < 0)
                             continue;
                     if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
                             warn ("connect(%s)", hostname);
                                 close (s);
                                 continue;
                     }
                     freeaddrinfo (ai);
                     ai = NULL;
             }
             if (ai) {
                         freeaddrinfo (ai);
                         errx ("failed to contact %s", hostname);
             }

Before authenticating, an authentication context needs to be created.
This context keeps all information for one (to be) authenticated
connection (see `krb5_auth_context(3)').

             status = krb5_auth_con_init (context, &auth_context);
             if (status)
                     krb5_err (context, 1, status, "krb5_auth_con_init");

For setting the address in the authentication there is a help function
`krb5_auth_con_setaddrs_from_fd' that does everything that is needed
when given a connected file descriptor to the socket.

             status = krb5_auth_con_setaddrs_from_fd (context,
                                                      auth_context,
                                                      &sock);
             if (status)
                     krb5_err (context, 1, status,
                               "krb5_auth_con_setaddrs_from_fd");

The next step is to build a server principal for the service we want to
connect to. (See also `krb5_sname_to_principal(3)'.)

             status = krb5_sname_to_principal (context,
                                               hostname,
                                               service,
                                               KRB5_NT_SRV_HST,
                                               &server);
             if (status)
                     krb5_err (context, 1, status, "krb5_sname_to_principal");

The client principal is not passed to `krb5_sendauth(3)' function, this
causes the `krb5_sendauth' function to try to figure it out itself.

The server program is using the function `krb5_recvauth(3)' to receive
the Kerberos 5 authenticator.

In this case, mutual authentication will be tried. That means that the
server will authenticate to the client. Using mutual authentication is
good since it enables the user to verify that they are talking to the
right server (a server that knows the key).

If you are using a non-blocking socket you will need to do all work of
`krb5_sendauth' yourself. Basically you need to send over the
authenticator from `krb5_mk_req(3)' and, in case of mutual
authentication, verifying the result from the server with
`krb5_rd_rep(3)'.

             status = krb5_sendauth (context,
                                     &auth_context,
                                     &sock,
                                     VERSION,
                                     NULL,
                                     server,
                                     AP_OPTS_MUTUAL_REQUIRED,
                                     NULL,
                                     NULL,
                                     NULL,
                                     NULL,
                                     NULL,
                                     NULL);
             if (status)
                     krb5_err (context, 1, status, "krb5_sendauth");

Once authentication has been performed, it is time to send some data.
First we create a krb5_data structure, then we sign it with
`krb5_mk_safe(3)' using the `auth_context' that contains the
session-key that was exchanged in the
`krb5_sendauth(3)'/`krb5_recvauth(3)' authentication sequence.

             data.data   = "hej";
             data.length = 3;
     
             krb5_data_zero (&packet);
     
             status = krb5_mk_safe (context,
                                    auth_context,
                                    &data,
                                    &packet,
                                    NULL);
             if (status)
                     krb5_err (context, 1, status, "krb5_mk_safe");

And send it over the network.

             len = packet.length;
             net_len = htonl(len);
     
             if (krb5_net_write (context, &sock, &net_len, 4) != 4)
                     err (1, "krb5_net_write");
             if (krb5_net_write (context, &sock, packet.data, len) != len)
                     err (1, "krb5_net_write");

To send encrypted (and signed) data `krb5_mk_priv(3)' should be used
instead. `krb5_mk_priv(3)' works the same way as `krb5_mk_safe(3)',
with the exception that it encrypts the data in addition to signing it.

             data.data   = "hemligt";
             data.length = 7;
     
             krb5_data_free (&packet);
     
             status = krb5_mk_priv (context,
                                    auth_context,
                                    &data,
                                    &packet,
                                    NULL);
             if (status)
                     krb5_err (context, 1, status, "krb5_mk_priv");

And send it over the network.

             len = packet.length;
             net_len = htonl(len);
     
             if (krb5_net_write (context, &sock, &net_len, 4) != 4)
                     err (1, "krb5_net_write");
             if (krb5_net_write (context, &sock, packet.data, len) != len)
                     err (1, "krb5_net_write");

The server is using `krb5_rd_safe(3)' and `krb5_rd_priv(3)' to verify
the signature and decrypt the packet.


File: heimdal.info,  Node: Validating a password in a server application,  Next: API differences to MIT Kerberos,  Prev: Walkthrough of a sample Kerberos 5 client,  Up: Programming with Kerberos

Validating a password in an application
=======================================

See the manual page for `krb5_verify_user(3)'.


File: heimdal.info,  Node: API differences to MIT Kerberos,  Next: File formats,  Prev: Validating a password in a server application,  Up: Programming with Kerberos

API differences to MIT Kerberos
===============================

This section is somewhat disorganised, but so far there is no overall
structure to the differences, though some of the have their root in
that Heimdal uses an ASN.1 compiler and MIT doesn't.

Principal and realms
--------------------

Heimdal stores the realm as a `krb5_realm', that is a `char *'.  MIT
Kerberos uses a `krb5_data' to store a realm.

In Heimdal `krb5_principal' doesn't contain the component `name_type';
it's instead stored in component `name.name_type'. To get and set the
nametype in Heimdal, use `krb5_principal_get_type(3)' and
`krb5_principal_set_type(3)'.

For more information about principal and realms, see
`krb5_principal(3)'.

Error messages
--------------

To get the error string, Heimdal uses `krb5_get_error_string(3)' or, if
`NULL' is returned, `krb5_get_err_text(3)'. This is to return custom
error messages (like "Can't find host/datan.example.com@EXAMPLE.COM in
/etc/krb5.conf." instead of a "Key table entry not found" that
`error_message(3)' returns.

Heimdal uses a threadsafe(r) version of the com_err interface; the
global `com_err' table isn't initialised.  Then `error_message(3)'
returns quite a boring error string (just the error code itself).


File: heimdal.info,  Node: File formats,  Prev: API differences to MIT Kerberos,  Up: Programming with Kerberos

File formats
============

This section documents the diffrent file formats that are used in
Heimdal and other Kerberos implementations.

keytab
------

The keytab binary format is not a standard format. The format has
evolved and may continue to. It is however understood by several
Kerberos implementations including Heimdal, MIT, Sun's Java ktab and
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;
       };

All numbers are stored in network byteorder (big endian) format.

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 in the components array.

The num_components field is followed by a counted_octet_string
representing the realm of the principal.

A counted_octet_string is simply an array of bytes prefixed with a 16
bit length. For the realm and name components, the counted_octet_string
bytes are ASCII encoded text with no zero terminator.

Following the realm is the components array that represents the name of
the principal. The text of these components may be joined with slashs
to construct the typical SPN representation. For example, the service
principal HTTP/www.foo.net@FOO.NET would consist of name components
"HTTP" followed by "www.foo.net".

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.

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 32 bit vno field if it is present. The vno8 field is
filled with the lower 8 bits of the 32 bit protocol kvno field.

The keyblock structure consists of a 16 bit value indicating the
encryption type and is a counted_octet_string containing the key.  The
encryption type is the same as the Kerberos standard (e.g. 3 is
des-cbc-md5, 23 is arcfour-hmac-md5, etc).

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
supersedes the 8 bit vno8 value preceeding the keyblock.

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

All integers are in host byte order [1].

The num_components field is 1 too large (i.e. after decoding, decrement by 1).

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.

Heimdal database dump file
--------------------------

Format of the Heimdal text dump file as of Heimdal 0.6.3:

Each line in the dump file is one entry in the database.

Each field of a line is separated by one or more spaces, with the
exception of fields consisting of principals containing spaces, where
space can be quoted with \ and \ is quoted by \.

Fields and their types are:

     	Quoted princial (quote character is \) [string]
     	Keys [keys]
     	Created by [event]
     	Modified by [event optional]
     	Valid start time [time optional]
     	Valid end time [time optional]
     	Password end valid time [time optional]
     	Max lifetime of ticket [time optional]
     	Max renew time of ticket [integer optional]
     	Flags [hdb flags]
     	Generation number [generation optional]
     	Extensions [extentions optional]

Fields following these silently are ignored.

All optional fields will be skipped if they fail to parse (or comprise
the optional field marker of "-", w/o quotes).

Example:

     fred@EXAMPLE.COM 27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:- 20020415130120:admin@EXAMPLE.COM 20041221112428:fred@EXAMPLE.COM - - - 86400 604800 126 20020415130120:793707:28 -

Encoding of types are as follows:

keys
          kvno:[masterkvno:keytype:keydata:salt]{zero or more separated by :}

     kvno is the key version number.

     keydata is hex-encoded

     masterkvno is the kvno of the database master key.  If this field
     is empty, the kadmin load and merge operations will encrypt the
     key data with the master key if there is one.  Otherwise the key
     data will be imported asis.

     salt is encoded as "-" (no/default salt) or

          salt-type /
          salt-type / "string"
          salt-type / hex-encoded-data

     keytype is the protocol enctype number; see enum ENCTYPE in
     include/krb5_asn1.h for values.

     Example:
          27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:-

          kvno=27,{key: masterkvno=1,keytype=des3-cbc-sha1,keydata=..., default salt}...

time
     Format of the time is: YYYYmmddHHMMSS, corresponding to strftime
     format "%Y%m%d%k%M%S".

     Time is expressed in UTC.

     Time can be optional (using -), when the time 0 is used.

     Example:

          20041221112428

event
          	time:principal

     time is as given in format time

     principal is a string.  Not quoting it may not work in earlier
     versions of Heimdal.

     Example:
          20041221112428:bloggs@EXAMPLE.COM

hdb flags
     Integer encoding of HDB flags, see HDBFlags in lib/hdb/hdb.asn1.
     Each bit in the integer is the same as the bit in the
     specification.

generation:
          time:usec:gen

     usec is a the microsecond, integer.  gen is generation number,
     integer.

     The generation can be defaulted (using '-') or the empty string

extensions:
          first-hex-encoded-HDB-Extension[:second-...]

     HDB-extension is encoded the DER encoded HDB-Extension from
     lib/hdb/hdb.asn1. Consumers HDB extensions should be aware that
     unknown entires needs to be preserved even thought the ASN.1 data
     content might be unknown. There is a critical flag in the data to
     show to the KDC that the entry MUST be understod if the entry is
     to be used.


File: heimdal.info,  Node: Migration,  Next: Acknowledgments,  Prev: Programming with Kerberos,  Up: Top

Migration
*********

General issues
==============

When migrating from a Kerberos 4 KDC.

Order in what to do things:
===========================

   * Convert the database, check all principals that hprop complains
     about.

     `hprop -n --source=<NNN>| hpropd -n'

     Replace <NNN> with whatever source you have, like krb4-db or
     krb4-dump.

   * Run a Kerberos 5 slave for a while.

   * Figure out if it does everything you want it to.

     Make sure that all things that you use works for you.

   * Let a small number of controlled users use Kerberos 5 tools.

     Find a sample population of your users and check what programs
     they use, you can also check the kdc-log to check what ticket are
     checked out.

   * Burn the bridge and change the master.

   * Let all users use the Kerberos 5 tools by default.

   * Turn off services that do not need Kerberos 4 authentication.

     Things that might be hard to get away is old programs with support
     for Kerberos 4. Example applications are old Eudora installations
     using KPOP, and Zephyr. Eudora can use the Kerberos 4 kerberos in
     the Heimdal kdc.



File: heimdal.info,  Node: Acknowledgments,  Prev: Migration,  Up: Top

Acknowledgments
***************

Eric Young wrote "libdes". Heimdal used to use libdes, without it
kth-krb would never have existed. Since there are no longer any Eric
Young code left in the library, we renamed it to libhcrypto.

All functions in libhcrypto have been re-implemented or used available
public domain code. The core AES function where written by Vincent
Rijmen, Antoon Bosselaers and Paulo Barreto.  The core DES SBOX
transformation was written by Richard Outerbridge. `imath' that is used
for public key crypto support is written by Michael J. Fromberger.

The University of California at Berkeley initially wrote `telnet', and
`telnetd'.  The authentication and encryption code of `telnet' and
`telnetd' was added by David Borman (then of Cray Research, Inc).  The
encryption code was removed when this was exported and then added back
by Juha Eskelinen.

The `popper' was also a Berkeley program initially.

Some of the functions in `libroken' also come from Berkeley by way of
NetBSD/FreeBSD.

`editline' was written by Simmule Turner and Rich Salz. Heimdal
contains a modifed copy.

The `getifaddrs' implementation for Linux was written by Hideaki
YOSHIFUJI for the Usagi project.

Bugfixes, documentation, encouragement, and code has been contributed
by:
Derrick J Brashear

Ken Hornstein

Johan Ihrén

Magnus Ahltorp

Mark Eichin

Marc Horowitz

Brandon S. Allbery KF8NH

Jun-ichiro itojun Hagino

Daniel Kouril

Åke Sandgren

Michal Vocu

Miroslav Ruda

Brian A May

Chaskiel M Grundman

Richard Nyberg

Frank van der Linden

Cizzi Storm

Petr Holub

Mario Strasser

David Love

Björn Sandell

Michael B Allen

Douglas E Engert

Jason McIntyre

and we hope that those not mentioned here will forgive us.
All bugs were introduced by ourselves.


