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