1@c $Id: programming.texi 22071 2007-11-14 20:04:50Z lha $
2
3@node Programming with Kerberos, Migration, Windows 2000 compatability, Top
4@chapter Programming with Kerberos
5
6First you need to know how the Kerberos model works, go read the
7introduction text (@pxref{What is Kerberos?}).
8
9@menu
10* Kerberos 5 API Overview::     
11* Walkthrough of a sample Kerberos 5 client::  
12* Validating a password in a server application::  
13* API differences to MIT Kerberos::  
14* File formats::
15@end menu
16
17@node Kerberos 5 API Overview, Walkthrough of a sample Kerberos 5 client, Programming with Kerberos, Programming with Kerberos
18@section Kerberos 5 API Overview
19
20All functions are documented in manual pages.  This section tries to
21give an overview of the major components used in Kerberos library, and
22point to where to look for a specific function.
23
24@subsection Kerberos context
25
26A kerberos context (@code{krb5_context}) holds all per thread state. All global variables that
27are context specific are stored in this structure, including default
28encryption types, credential cache (for example, a ticket file), and default realms.
29
30See the manual pages for @manpage{krb5_context,3} and
31@manpage{krb5_init_context,3}.
32
33@subsection Kerberos authentication context
34
35Kerberos authentication context (@code{krb5_auth_context}) holds all
36context related to an authenticated connection, in a similar way to the
37kerberos context that holds the context for the thread or process.
38
39The @code{krb5_auth_context} is used by various functions that are
40directly related to authentication between the server/client. Example of
41data that this structure contains are various flags, addresses of client
42and server, port numbers, keyblocks (and subkeys), sequence numbers,
43replay cache, and checksum types.
44
45See the manual page for @manpage{krb5_auth_context,3}.
46
47@subsection Kerberos principal
48
49The Kerberos principal is the structure that identifies a user or
50service in Kerberos. The structure that holds the principal is the
51@code{krb5_principal}. There are function to extract the realm and
52elements of the principal, but most applications have no reason to
53inspect the content of the structure.
54
55The are several ways to create a principal (with different degree of
56portability), and one way to free it.
57
58See manual page for @manpage{krb5_principal,3} for more information
59about the functions.
60
61@subsection Credential cache
62
63A credential cache holds the tickets for a user. A given user can have
64several credential caches, one for each realm where the user have the
65initial tickets (the first krbtgt).
66
67The credential cache data can be stored internally in different way, each of them for
68different proposes.  File credential (FILE) caches and processes based
69(KCM) caches are for permanent storage. While memory caches (MEMORY)
70are local caches to the local process.
71
72Caches are opened with @manpage{krb5_cc_resolve,3} or created with
73@manpage{krb5_cc_gen_unique,3}.
74
75If the cache needs to be opened again (using
76@manpage{krb5_cc_resolve,3}) @manpage{krb5_cc_close,3} will close the
77handle, but not the remove the cache. @manpage{krb5_cc_destroy,3} will
78zero out the cache, remove the cache so it can no longer be
79referenced.
80
81See also manual page for @manpage{krb5_ccache,3}
82
83@subsection Kerberos errors
84
85Kerberos errors are based on the com_err library.  All error codes are
8632-bit signed numbers, the first 24 bits define what subsystem the
87error originates from, and last 8 bits are 255 error codes within the
88library.  Each error code have fixed string associated with it.  For
89example, the error-code -1765328383 have the symbolic name
90KRB5KDC_ERR_NAME_EXP, and associated error string ``Client's entry in
91database has expired''.
92
93This is a great improvement compared to just getting one of the unix
94error-codes back.  However, Heimdal have an extention to pass back
95customised errors messages.  Instead of getting ``Key table entry not
96found'', the user might back ``failed to find
97host/host.example.com@@EXAMLE.COM(kvno 3) in keytab /etc/krb5.keytab
98(des-cbc-crc)''.  This improves the chance that the user find the
99cause of the error so you should use the customised error message
100whenever it's available.
101
102See also manual page for @manpage{krb5_get_error_string,3} and
103@manpage{krb5_get_err_text,3}.
104
105@subsection Keytab management
106
107A keytab is a storage for locally stored keys. Heimdal includes keytab
108support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's,
109and for storing keys in memory.
110
111Keytabs are used for servers and long-running services.
112
113See also manual page for @manpage{krb5_keytab,3}
114
115@subsection Kerberos crypto
116
117Heimdal includes a implementation of the Kerberos crypto framework,
118all crypto operations.
119
120See also manual page for @manpage{krb5_crypto_init,3},
121@manpage{krb5_keyblock,3}, @manpage{krb5_create_checksum,3}, 
122and @manpage{krb5_encrypt,3}.
123
124@node Walkthrough of a sample Kerberos 5 client, Validating a password in a server application, Kerberos 5 API Overview, Programming with Kerberos
125@section Walkthrough of a sample Kerberos 5 client
126
127This example contains parts of a sample TCP Kerberos 5 clients, if you
128want a real working client, please look in @file{appl/test} directory in
129the Heimdal distribution.
130
131All Kerberos error-codes that are returned from kerberos functions in
132this program are passed to @code{krb5_err}, that will print a
133descriptive text of the error code and exit. Graphical programs can
134convert error-code to a human readable error-string with the
135@manpage{krb5_get_err_text,3} function.
136
137Note that you should not use any Kerberos function before
138@code{krb5_init_context()} have completed successfully. That is the
139reason @code{err()} is used when @code{krb5_init_context()} fails.
140
141First the client needs to call @code{krb5_init_context} to initialise
142the Kerberos 5 library. This is only needed once per thread
143in the program. If the function returns a non-zero value it indicates
144that either the Kerberos implementation is failing or it's disabled on
145this host.
146
147@example
148#include <krb5.h>
149
150int
151main(int argc, char **argv)
152@{
153        krb5_context context;
154
155        if (krb5_context(&context))
156                errx (1, "krb5_context");
157@end example
158
159Now the client wants to connect to the host at the other end. The
160preferred way of doing this is using @manpage{getaddrinfo,3} (for
161operating system that have this function implemented), since getaddrinfo
162is neutral to the address type and can use any protocol that is available.
163
164@example
165        struct addrinfo *ai, *a;
166        struct addrinfo hints;
167        int error;
168
169        memset (&hints, 0, sizeof(hints));
170        hints.ai_socktype = SOCK_STREAM;
171        hints.ai_protocol = IPPROTO_TCP;
172
173        error = getaddrinfo (hostname, "pop3", &hints, &ai);
174        if (error)
175                errx (1, "%s: %s", hostname, gai_strerror(error));
176
177        for (a = ai; a != NULL; a = a->ai_next) @{
178                int s;
179
180                s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
181                if (s < 0)
182                        continue;
183                if (connect (s, a->ai_addr, a->ai_addrlen) < 0) @{
184                        warn ("connect(%s)", hostname);
185                            close (s);
186                            continue;
187                @}
188                freeaddrinfo (ai);
189                ai = NULL;
190        @}
191        if (ai) @{
192                    freeaddrinfo (ai);
193                    errx ("failed to contact %s", hostname);
194        @}
195@end example
196
197Before authenticating, an authentication context needs to be
198created. This context keeps all information for one (to be) authenticated
199connection (see @manpage{krb5_auth_context,3}).
200
201@example
202        status = krb5_auth_con_init (context, &auth_context);
203        if (status)
204                krb5_err (context, 1, status, "krb5_auth_con_init");
205@end example
206
207For setting the address in the authentication there is a help function
208@code{krb5_auth_con_setaddrs_from_fd} that does everything that is needed
209when given a connected file descriptor to the socket.
210
211@example
212        status = krb5_auth_con_setaddrs_from_fd (context,
213                                                 auth_context,
214                                                 &sock);
215        if (status)
216                krb5_err (context, 1, status, 
217                          "krb5_auth_con_setaddrs_from_fd");
218@end example
219
220The next step is to build a server principal for the service we want
221to connect to. (See also @manpage{krb5_sname_to_principal,3}.)
222
223@example
224        status = krb5_sname_to_principal (context,
225                                          hostname,
226                                          service,
227                                          KRB5_NT_SRV_HST,
228                                          &server);
229        if (status)
230                krb5_err (context, 1, status, "krb5_sname_to_principal");
231@end example
232
233The client principal is not passed to @manpage{krb5_sendauth,3}
234function, this causes the @code{krb5_sendauth} function to try to figure it
235out itself.
236
237The server program is using the function @manpage{krb5_recvauth,3} to
238receive the Kerberos 5 authenticator.
239
240In this case, mutual authentication will be tried. That means that the server
241will authenticate to the client. Using mutual authentication
242is good since it enables the user to verify that they are talking to the
243right server (a server that knows the key).
244
245If you are using a non-blocking socket you will need to do all work of
246@code{krb5_sendauth} yourself. Basically you need to send over the
247authenticator from @manpage{krb5_mk_req,3} and, in case of mutual
248authentication, verifying the result from the server with
249@manpage{krb5_rd_rep,3}.
250
251@example
252        status = krb5_sendauth (context,
253                                &auth_context,
254                                &sock,
255                                VERSION,
256                                NULL,
257                                server,
258                                AP_OPTS_MUTUAL_REQUIRED,
259                                NULL,
260                                NULL,
261                                NULL,
262                                NULL,
263                                NULL,
264                                NULL);
265        if (status)
266                krb5_err (context, 1, status, "krb5_sendauth");
267@end example
268
269Once authentication has been performed, it is time to send some
270data. First we create a krb5_data structure, then we sign it with
271@manpage{krb5_mk_safe,3} using the @code{auth_context} that contains the
272session-key that was exchanged in the
273@manpage{krb5_sendauth,3}/@manpage{krb5_recvauth,3} authentication
274sequence.
275
276@example
277        data.data   = "hej";
278        data.length = 3;
279
280        krb5_data_zero (&packet);
281
282        status = krb5_mk_safe (context,
283                               auth_context,
284                               &data,
285                               &packet,
286                               NULL);
287        if (status)
288                krb5_err (context, 1, status, "krb5_mk_safe");
289@end example
290
291And send it over the network.
292
293@example
294        len = packet.length;
295        net_len = htonl(len);
296
297        if (krb5_net_write (context, &sock, &net_len, 4) != 4)
298                err (1, "krb5_net_write");
299        if (krb5_net_write (context, &sock, packet.data, len) != len)
300                err (1, "krb5_net_write");
301@end example
302
303To send encrypted (and signed) data @manpage{krb5_mk_priv,3} should be
304used instead. @manpage{krb5_mk_priv,3} works the same way as
305@manpage{krb5_mk_safe,3}, with the exception that it encrypts the data
306in addition to signing it.
307
308@example
309        data.data   = "hemligt";
310        data.length = 7;
311
312        krb5_data_free (&packet);
313
314        status = krb5_mk_priv (context,
315                               auth_context,
316                               &data,
317                               &packet,
318                               NULL);
319        if (status)
320                krb5_err (context, 1, status, "krb5_mk_priv");
321@end example
322
323And send it over the network.
324
325@example
326        len = packet.length;
327        net_len = htonl(len);
328
329        if (krb5_net_write (context, &sock, &net_len, 4) != 4)
330                err (1, "krb5_net_write");
331        if (krb5_net_write (context, &sock, packet.data, len) != len)
332                err (1, "krb5_net_write");
333
334@end example
335
336The server is using @manpage{krb5_rd_safe,3} and
337@manpage{krb5_rd_priv,3} to verify the signature and decrypt the packet.
338
339@node Validating a password in a server application, API differences to MIT Kerberos, Walkthrough of a sample Kerberos 5 client, Programming with Kerberos
340@section Validating a password in an application
341
342See the manual page for @manpage{krb5_verify_user,3}.
343
344@node API differences to MIT Kerberos, File formats, Validating a password in a server application, Programming with Kerberos
345@section API differences to MIT Kerberos
346
347This section is somewhat disorganised, but so far there is no overall
348structure to the differences, though some of the have their root in
349that Heimdal uses an ASN.1 compiler and MIT doesn't.
350
351@subsection Principal and realms
352
353Heimdal stores the realm as a @code{krb5_realm}, that is a @code{char *}.
354MIT Kerberos uses a @code{krb5_data} to store a realm.
355
356In Heimdal @code{krb5_principal} doesn't contain the component
357@code{name_type}; it's instead stored in component
358@code{name.name_type}. To get and set the nametype in Heimdal, use
359@manpage{krb5_principal_get_type,3} and
360@manpage{krb5_principal_set_type,3}.
361
362For more information about principal and realms, see
363@manpage{krb5_principal,3}.
364
365@subsection Error messages
366
367To get the error string, Heimdal uses
368@manpage{krb5_get_error_string,3} or, if @code{NULL} is returned,
369@manpage{krb5_get_err_text,3}. This is to return custom error messages
370(like ``Can't find host/datan.example.com@@EXAMPLE.COM in
371/etc/krb5.conf.'' instead of a ``Key table entry not found'' that
372@manpage{error_message,3} returns.
373
374Heimdal uses a threadsafe(r) version of the com_err interface; the
375global @code{com_err} table isn't initialised.  Then
376@manpage{error_message,3} returns quite a boring error string (just
377the error code itself).
378
379
380@c @node Why you should use GSS-API for new applications, Walkthrough of a sample GSS-API client, Validating a password in a server application, Programming with Kerberos
381@c @section Why you should use GSS-API for new applications
382@c 
383@c SSPI, bah, bah, microsoft, bah, bah, almost GSS-API.
384@c 
385@c It would also be possible for other mechanisms then Kerberos, but that
386@c doesn't exist any other GSS-API implementations today.
387@c 
388@c @node Walkthrough of a sample GSS-API client, , Why you should use GSS-API for new applications, Programming with Kerberos
389@c @section Walkthrough of a sample GSS-API client
390@c 
391@c Write about how gssapi_clent.c works.
392
393@node File formats,  , API differences to MIT Kerberos, Programming with Kerberos
394@section File formats
395
396This section documents the diffrent file formats that are used in
397Heimdal and other Kerberos implementations.
398
399@subsection keytab
400
401The keytab binary format is not a standard format. The format has
402evolved and may continue to. It is however understood by several
403Kerberos implementations including Heimdal, MIT, Sun's Java ktab and
404are created by the ktpass.exe utility from Windows. So it has
405established itself as the defacto format for storing Kerberos keys.
406
407The following C-like structure definitions illustrate the MIT keytab
408file format. All values are in network byte order. All text is ASCII.
409
410@example
411  keytab @{
412      uint16_t file_format_version;                    /* 0x502 */
413      keytab_entry entries[*];
414  @};
415
416  keytab_entry @{
417      int32_t size;
418      uint16_t num_components;   /* subtract 1 if version 0x501 */
419      counted_octet_string realm;
420      counted_octet_string components[num_components];
421      uint32_t name_type;       /* not present if version 0x501 */
422      uint32_t timestamp;
423      uint8_t vno8;
424      keyblock key;
425      uint32_t vno; /* only present if >= 4 bytes left in entry */
426  @};
427
428  counted_octet_string @{
429      uint16_t length;
430      uint8_t data[length];
431  @};
432
433  keyblock @{
434      uint16_t type;
435      counted_octet_string;
436  @};
437@end example
438
439All numbers are stored in network byteorder (big endian) format.
440
441The keytab file format begins with the 16 bit file_format_version which
442at the time this document was authored is 0x502. The format of older
443keytabs is described at the end of this document.
444
445The file_format_version is immediately followed by an array of
446keytab_entry structures which are prefixed with a 32 bit size indicating
447the number of bytes that follow in the entry. Note that the size should be
448evaluated as signed. This is because a negative value indicates that the
449entry is in fact empty (e.g. it has been deleted) and that the negative
450value of that negative value (which is of course a positive value) is
451the offset to the next keytab_entry. Based on these size values alone
452the entire keytab file can be traversed.
453
454The size is followed by a 16 bit num_components field indicating the
455number of counted_octet_string components in the components array.
456
457The num_components field is followed by a counted_octet_string
458representing the realm of the principal.
459
460A counted_octet_string is simply an array of bytes prefixed with a 16
461bit length. For the realm and name components, the counted_octet_string
462bytes are ASCII encoded text with no zero terminator.
463
464Following the realm is the components array that represents the name of
465the principal. The text of these components may be joined with slashs
466to construct the typical SPN representation. For example, the service
467principal HTTP/www.foo.net@@FOO.NET would consist of name components
468"HTTP" followed by "www.foo.net".
469
470Following the components array is the 32 bit name_type (e.g. 1 is
471KRB5_NT_PRINCIPAL, 2 is KRB5_NT_SRV_INST, 5 is KRB5_NT_UID, etc). In
472practice the name_type is almost certainly 1 meaning KRB5_NT_PRINCIPAL.
473
474The 32 bit timestamp indicates the time the key was established for that
475principal. The value represents the number of seconds since Jan 1, 1970.
476
477The 8 bit vno8 field is the version number of the key. This value is
478overridden by the 32 bit vno field if it is present. The vno8 field is
479filled with the lower 8 bits of the 32 bit protocol kvno field.
480
481The keyblock structure consists of a 16 bit value indicating the
482encryption type and is a counted_octet_string containing the key.  The
483encryption type is the same as the Kerberos standard (e.g. 3 is
484des-cbc-md5, 23 is arcfour-hmac-md5, etc).
485
486The last field of the keytab_entry structure is optional. If the size of
487the keytab_entry indicates that there are at least 4 bytes remaining,
488a 32 bit value representing the key version number is present. This
489value supersedes the 8 bit vno8 value preceeding the keyblock.
490
491Older keytabs with a file_format_version of 0x501 are different in
492three ways:
493
494@table @asis
495@item All integers are in host byte order [1].
496@item The num_components field is 1 too large (i.e. after decoding, decrement by 1).
497@item The 32 bit name_type field is not present.
498@end table
499
500[1] The file_format_version field should really be treated as two
501separate 8 bit quantities representing the major and minor version
502number respectively.
503
504@subsection Heimdal database dump file
505
506Format of the Heimdal text dump file as of Heimdal 0.6.3:
507
508Each line in the dump file is one entry in the database.
509
510Each field of a line is separated by one or more spaces, with the
511exception of fields consisting of principals containing spaces, where
512space can be quoted with \ and \ is quoted by \.
513
514Fields and their types are:
515
516@example
517	Quoted princial (quote character is \) [string]
518	Keys [keys]
519	Created by [event]
520	Modified by [event optional]
521	Valid start time [time optional]
522	Valid end time [time optional]
523	Password end valid time [time optional]
524	Max lifetime of ticket [time optional]
525	Max renew time of ticket [integer optional]
526	Flags [hdb flags]
527	Generation number [generation optional]
528	Extensions [extentions optional]
529@end example
530
531Fields following these silently are ignored.
532
533All optional fields will be skipped if they fail to parse (or comprise
534the optional field marker of "-", w/o quotes).
535
536Example:
537
538@example
539fred@@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 -
540@end example
541
542Encoding of types are as follows:
543
544@table @asis
545@item keys
546
547@example
548kvno:[masterkvno:keytype:keydata:salt]@{zero or more separated by :@}
549@end example
550
551kvno is the key version number.
552
553keydata is hex-encoded
554
555masterkvno is the kvno of the database master key.  If this field is
556empty, the kadmin load and merge operations will encrypt the key data
557with the master key if there is one.  Otherwise the key data will be
558imported asis.
559
560salt is encoded as "-" (no/default salt) or
561
562@example
563salt-type /
564salt-type / "string"
565salt-type / hex-encoded-data
566@end example
567
568keytype is the protocol enctype number; see enum ENCTYPE in
569include/krb5_asn1.h for values.
570
571Example:
572@example
57327:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:-
574@end example
575
576
577@example
578kvno=27,@{key: masterkvno=1,keytype=des3-cbc-sha1,keydata=..., default salt@}...
579@end example
580
581@item time
582	
583Format of the time is: YYYYmmddHHMMSS, corresponding to strftime
584format "%Y%m%d%k%M%S".
585
586Time is expressed in UTC.
587
588Time can be optional (using -), when the time 0 is used.
589
590Example:
591
592@example
59320041221112428
594@end example
595
596@item event
597
598@example
599	time:principal
600@end example
601
602time is as given in format time
603
604principal is a string.  Not quoting it may not work in earlier
605versions of Heimdal.
606
607Example:
608@example
60920041221112428:bloggs@@EXAMPLE.COM
610@end example
611
612@item hdb flags
613
614Integer encoding of HDB flags, see HDBFlags in lib/hdb/hdb.asn1. Each
615bit in the integer is the same as the bit in the specification.
616
617@item generation:
618
619@example
620time:usec:gen
621@end example
622
623
624usec is a the microsecond, integer.
625gen is generation number, integer.
626
627The generation can be defaulted (using '-') or the empty string
628
629@item extensions:
630
631@example
632first-hex-encoded-HDB-Extension[:second-...]
633@end example
634
635HDB-extension is encoded the DER encoded HDB-Extension from
636lib/hdb/hdb.asn1. Consumers HDB extensions should be aware that
637unknown entires needs to be preserved even thought the ASN.1 data
638content might be unknown. There is a critical flag in the data to show
639to the KDC that the entry MUST be understod if the entry is to be
640used.
641
642@end table
643