Use new xreadlink interface.
[shishi.git] / src / kdc.c
blobb75c705f4fd9bdece63d4165bd3dc5cd0b9fbb76
1 /* kdc.c --- Process AS and TGS requests.
2 * Copyright (C) 2002, 2003, 2004, 2005 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Shishi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Shishi; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 /* Note: only use syslog to report errors in this file. */
24 /* Get Shishid stuff. */
25 #include "kdc.h"
27 static int
28 asreq1 (Shishi_as * as)
30 Shishi_tkt *tkt;
31 Shishi_key *serverkey = NULL, *sessionkey = NULL, *userkey = NULL;
32 Shisa_key *userdbkey = NULL;
33 Shisa_key **serverkeys = NULL, **userkeys = NULL;
34 size_t nserverkeys, nuserkeys;
35 int rc;
36 char *username = NULL, *servername = NULL, *realm = NULL;
37 Shisa_principal server, user;
38 uint32_t sessionkeytype = -1;
39 int32_t etype;
40 int i;
43 * The authentication server looks up the client and server principals
44 * named in the KRB_AS_REQ in its database, extracting their respective
45 * keys. If the requested client principal named in the request is not
46 * known because it doesn't exist in the KDC's principal database, then
47 * an error message with a KDC_ERR_C_PRINCIPAL_UNKNOWN is returned.
50 rc = shishi_kdcreq_realm (handle, shishi_as_req (as), &realm, NULL);
51 if (rc != SHISHI_OK)
53 syslog (LOG_ERR, "shishi_kdcreq_realm failed (%d): %s",
54 rc, shishi_strerror (rc));
55 goto fatal;
58 rc = shishi_kdcreq_client (handle, shishi_as_req (as), &username, NULL);
59 if (rc != SHISHI_OK)
61 syslog (LOG_ERR, "shishi_kdcreq_client failed (%d): %s",
62 rc, shishi_strerror (rc));
63 goto fatal;
66 rc = shishi_kdcreq_server (handle, shishi_as_req (as), &servername, NULL);
67 if (rc != SHISHI_OK)
69 syslog (LOG_ERR, "shishi_kdcreq_server failed (%d): %s",
70 rc, shishi_strerror (rc));
71 goto fatal;
74 /* Find the client, e.g., simon@JOSEFSSON.ORG. */
76 rc = shisa_principal_find (dbh, realm, username, &user);
77 if (rc != SHISA_OK && rc != SHISA_NO_PRINCIPAL)
79 syslog (LOG_ERR, "shisa_principal_find failed (%d): %s",
80 rc, shisa_strerror (rc));
81 rc = SHISHI_INVALID_PRINCIPAL_NAME;
82 goto fatal;
84 if (rc == SHISA_NO_PRINCIPAL)
86 syslog (LOG_NOTICE, "AS-REQ from %s@%s for %s@%s failed: no such user",
87 username, realm, servername, realm);
88 rc = shishi_krberror_errorcode_set (handle, shishi_as_krberror (as),
89 SHISHI_KDC_ERR_C_PRINCIPAL_UNKNOWN);
90 if (rc != SHISHI_OK)
91 goto fatal;
92 rc = SHISHI_INVALID_PRINCIPAL_NAME;
93 goto fatal;
96 rc = shisa_keys_find (dbh, realm, username, NULL, &userkeys, &nuserkeys);
97 if (rc != SHISA_OK || nuserkeys == 0)
99 syslog (LOG_ERR, "shisa_keys_find(%s@%s) failed (%d): %s",
100 username, realm, rc, shisa_strerror (rc));
101 rc = SHISHI_INVALID_PRINCIPAL_NAME;
102 goto fatal;
105 /* Find the server, e.g., krbtgt/JOSEFSSON.ORG@JOSEFSSON.ORG. */
107 rc = shisa_principal_find (dbh, realm, servername, &server);
108 if (rc != SHISA_OK && rc != SHISA_NO_PRINCIPAL)
110 syslog (LOG_ERR, "shisa_principal_find failed (%d): %s",
111 rc, shisa_strerror (rc));
112 rc = SHISHI_INVALID_PRINCIPAL_NAME;
113 goto fatal;
115 if (rc == SHISA_NO_PRINCIPAL)
117 syslog (LOG_NOTICE,
118 "AS-REQ from %s@%s for %s@%s failed: no such server", username,
119 realm, servername, realm);
120 rc =
121 shishi_krberror_errorcode_set (handle, shishi_as_krberror (as),
122 SHISHI_KDC_ERR_S_PRINCIPAL_UNKNOWN);
123 if (rc != SHISHI_OK)
124 goto fatal;
125 rc = SHISHI_INVALID_PRINCIPAL_NAME;
126 goto fatal;
129 rc = shisa_keys_find (dbh, realm, servername, NULL,
130 &serverkeys, &nserverkeys);
131 if (rc != SHISA_OK || nserverkeys == 0)
133 syslog (LOG_ERR, "shisa_keys_find(%s@%s) failed (%d): %s",
134 servername, realm, rc, shisa_strerror (rc));
135 rc = SHISHI_INVALID_PRINCIPAL_NAME;
136 goto fatal;
139 syslog (LOG_INFO, "AS-REQ from %s@%s for %s@%s", username, realm,
140 servername, realm);
143 * If required, the server pre-authenticates the request, and if the
144 * pre-authentication check fails, an error message with the code
145 * KDC_ERR_PREAUTH_FAILED is returned. If pre-authentication is
146 * required, but was not present in the request, an error message with
147 * the code KDC_ERR_PREAUTH_REQUIRED is returned and a METHOD-DATA
148 * object will be stored in the e-data field of the KRB-ERROR message to
149 * specify which pre-authentication mechanisms are acceptable. Usually
150 * this will include PA-ETYPE-INFO and/or PA-ETYPE-INFO2 elements as
151 * described below. If the server cannot accommodate any encryption type
152 * requested by the client, an error message with code
153 * KDC_ERR_ETYPE_NOSUPP is returned. Otherwise the KDC generates a
154 * 'random' session key[7].
157 /* XXX support pre-auth. */
160 * When responding to an AS request, if there are multiple encryption
161 * keys registered for a client in the Kerberos database, then the etype
162 * field from the AS request is used by the KDC to select the encryption
163 * method to be used to protect the encrypted part of the KRB_AS_REP
164 * message which is sent to the client. If there is more than one
165 * supported strong encryption type in the etype list, the KDC SHOULD
166 * use the first valid strong etype for which an encryption key is
167 * available.
170 for (i = 1; (rc = shishi_kdcreq_etype (handle, shishi_as_req (as),
171 &etype, i)) == SHISHI_OK; i++)
173 size_t j;
175 if (!shishi_cipher_supported_p (etype))
176 continue;
178 if (sessionkeytype == -1)
179 for (j = 0; j < nserverkeys; j++)
180 if (serverkeys[j]->etype == etype)
181 sessionkeytype = serverkeys[j]->etype;
183 if (userdbkey == NULL)
184 for (j = 0; j < nuserkeys; j++)
186 syslog (LOG_DEBUG,
187 "Matching client etype %d against user key etype %d",
188 etype, userkeys[j]->etype);
189 if (userkeys[j]->etype == etype)
190 userdbkey = userkeys[j];
194 if (userdbkey == NULL)
196 syslog (LOG_NOTICE, "No matching client keys for %s@%s",
197 username, realm);
198 rc = shishi_krberror_errorcode_set (handle, shishi_as_krberror (as),
199 SHISHI_KDC_ERR_ETYPE_NOSUPP);
200 if (rc != SHISHI_OK)
201 goto fatal;
202 rc = SHISHI_INVALID_PRINCIPAL_NAME;
203 goto fatal;
207 rc = shishi_key_from_value (handle, userdbkey->etype,
208 userdbkey->key, &userkey);
209 if (rc != SHISHI_OK)
211 syslog (LOG_ERR, "shishi_key_from_value (user) failed (%d): %s",
212 rc, shishi_strerror (rc));
213 goto fatal;
216 /* XXX Select "best" available key (highest kvno, best algorithm?)
217 here. The client etype should not influence this. */
218 rc = shishi_key_from_value (handle, serverkeys[0]->etype,
219 serverkeys[0]->key, &serverkey);
220 if (rc != SHISHI_OK)
222 syslog (LOG_ERR, "shishi_key_from_value (server) failed (%d): %s",
223 rc, shishi_strerror (rc));
224 goto fatal;
227 * When the user's key is generated from a password or pass phrase, the
228 * string-to-key function for the particular encryption key type is
229 * used, as specified in [@KCRYPTO]. The salt value and additional
230 * parameters for the string-to-key function have default values
231 * (specified by section 4 and by the encryption mechanism
232 * specification, respectively) that may be overridden by pre-
233 * authentication data (PA-PW-SALT, PA-AFS3-SALT, PA-ETYPE-INFO, PA-
234 * ETYPE-INFO2, etc). Since the KDC is presumed to store a copy of the
235 * resulting key only, these values should not be changed for password-
236 * based keys except when changing the principal's key.
238 * When the AS server is to include pre-authentication data in a KRB-
239 * ERROR or in an AS-REP, it MUST use PA-ETYPE-INFO2, not PA-ETYPE-INFO,
240 * if the etype field of the client's AS-REQ lists at least one "newer"
241 * encryption type. Otherwise (when the etype field of the client's AS-
242 * REQ does not list any "newer" encryption types) it MUST send both,
243 * PA-ETYPE-INFO2 and PA-ETYPE-INFO (both with an entry for each
244 * enctype). A "newer" enctype is any enctype first officially
245 * specified concurrently with or subsequent to the issue of this RFC.
246 * The enctypes DES, 3DES or RC4 and any defined in [RFC1510] are not
247 * newer enctypes.
249 * It is not possible to reliably generate a user's key given a pass
250 * phrase without contacting the KDC, since it will not be known whether
251 * alternate salt or parameter values are required.
255 /* XXX support pre-auth. */
258 * The KDC will attempt to assign the type of the random session key
259 * from the list of methods in the etype field. The KDC will select the
260 * appropriate type using the list of methods provided together with
261 * information from the Kerberos database indicating acceptable
262 * encryption methods for the application server. The KDC will not issue
263 * tickets with a weak session key encryption type.
266 if (sessionkeytype == -1)
267 sessionkeytype = shishi_cfg_clientkdcetype_fast (handle);
269 rc = shishi_key_random (handle, sessionkeytype, &sessionkey);
270 if (rc != SHISHI_OK)
272 syslog (LOG_ERR, "shishi_key_random (session key) failed (%d): %s",
273 rc, shishi_strerror (rc));
274 goto fatal;
278 * If the requested start time is absent, indicates a time in the past,
279 * or is within the window of acceptable clock skew for the KDC and the
280 * POSTDATE option has not been specified, then the start time of the
281 * ticket is set to the authentication server's current time. If it
282 * indicates a time in the future beyond the acceptable clock skew, but
283 * the POSTDATED option has not been specified then the error
284 * KDC_ERR_CANNOT_POSTDATE is returned. Otherwise the requested start
285 * time is checked against the policy of the local realm (the
286 * administrator might decide to prohibit certain types or ranges of
287 * postdated tickets), and if acceptable, the ticket's start time is set
288 * as requested and the INVALID flag is set in the new ticket. The
289 * postdated ticket MUST be validated before use by presenting it to the
290 * KDC after the start time has been reached.
292 * The expiration time of the ticket will be set to the earlier of the
293 * requested endtime and a time determined by local policy, possibly
294 * determined using realm or principal specific factors. For example,
295 * the expiration time MAY be set to the earliest of the following:
297 * * The expiration time (endtime) requested in the KRB_AS_REQ
298 * message.
300 * * The ticket's start time plus the maximum allowable lifetime
301 * associated with the client principal from the authentication
302 * server's database.
304 * * The ticket's start time plus the maximum allowable lifetime
305 * associated with the server principal.
307 * * The ticket's start time plus the maximum lifetime set by the
308 * policy of the local realm.
310 * If the requested expiration time minus the start time (as determined
311 * above) is less than a site-determined minimum lifetime, an error
312 * message with code KDC_ERR_NEVER_VALID is returned. If the requested
313 * expiration time for the ticket exceeds what was determined as above,
314 * and if the 'RENEWABLE-OK' option was requested, then the 'RENEWABLE'
315 * flag is set in the new ticket, and the renew-till value is set as if
316 * the 'RENEWABLE' option were requested (the field and option names are
317 * described fully in section 5.4.1).
319 * If the RENEWABLE option has been requested or if the RENEWABLE-OK
320 * option has been set and a renewable ticket is to be issued, then the
321 * renew-till field MAY be set to the earliest of:
323 * * Its requested value.
325 * * The start time of the ticket plus the minimum of the two
326 * maximum renewable lifetimes associated with the principals'
327 * database entries.
329 * * The start time of the ticket plus the maximum renewable
330 * lifetime set by the policy of the local realm.
334 tkt = shishi_as_tkt (as);
335 if (tkt == NULL)
337 syslog (LOG_ERR, "shishi_as_tkt failed");
338 goto fatal;
342 char *till;
343 size_t tilllen;
345 rc = shishi_kdcreq_till (handle, shishi_as_req (as), &till, &tilllen);
346 if (rc != SHISHI_OK)
348 syslog (LOG_ERR, "shishi_kdcreq_till failed (%d): %s",
349 rc, shishi_strerror (rc));
350 goto fatal;
353 if (tilllen != 16 || strlen (till) != 15)
355 syslog (LOG_ERR, "Invalid 'till' field in request (%d): %s", tilllen,
356 till);
357 goto fatal;
360 rc = shishi_encticketpart_endtime_set (handle,
361 shishi_tkt_encticketpart (tkt),
362 till);
364 free (till);
367 /* XXX Do the time stuff above. */
370 * The flags field of the new ticket will have the following options set
371 * if they have been requested and if the policy of the local realm
372 * allows: FORWARDABLE, MAY-POSTDATE, POSTDATED, PROXIABLE, RENEWABLE.
373 * If the new ticket is postdated (the start time is in the future), its
374 * INVALID flag will also be set.
377 if (shishi_kdcreq_forwardable_p (handle, shishi_as_req (as)))
378 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_FORWARDABLE);
380 if (shishi_kdcreq_allow_postdate_p (handle, shishi_as_req (as)))
381 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_MAY_POSTDATE);
383 if (shishi_kdcreq_postdated_p (handle, shishi_as_req (as)))
385 /* XXX policy check from time. */
386 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_POSTDATED);
387 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_INVALID);
388 /* XXX set starttime to from */
391 if (shishi_kdcreq_proxiable_p (handle, shishi_as_req (as)))
392 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_PROXIABLE);
394 if (shishi_kdcreq_renewable_p (handle, shishi_as_req (as)))
396 shishi_tkt_flags_add (tkt, SHISHI_TICKETFLAGS_RENEWABLE);
397 /* XXX set renew-till from rtime */
401 * If all of the above succeed, the server will encrypt the ciphertext
402 * part of the ticket using the encryption key extracted from the server
403 * principal's record in the Kerberos database using the encryption type
404 * associated with the server principal's key (this choice is NOT
405 * affected by the etype field in the request). It then formats a
406 * KRB_AS_REP message (see section 5.4.2), copying the addresses in the
407 * request into the caddr of the response, placing any required pre-
408 * authentication data into the padata of the response, and encrypts the
409 * ciphertext part in the client's key using an acceptable encryption
410 * method requested in the etype field of the request, or in some key
411 * specified by pre-authentication mechanisms being used.
414 rc = shishi_tkt_key_set (tkt, sessionkey);
415 if (rc != SHISHI_OK)
417 syslog (LOG_ERR, "shishi_tkt_key_set failed (%d): %s",
418 rc, shishi_strerror (rc));
419 goto fatal;
422 rc = shishi_tkt_clientrealm_set (tkt, realm, username);
423 if (rc != SHISHI_OK)
425 syslog (LOG_ERR, "shishi_tkt_clientrealm_set failed (%d): %s",
426 rc, shishi_strerror (rc));
427 goto fatal;
430 rc = shishi_tkt_serverrealm_set (tkt, realm, servername);
431 if (rc != SHISHI_OK)
433 syslog (LOG_ERR, "shishi_tkt_serverrealm_set failed (%d): %s",
434 rc, shishi_strerror (rc));
435 goto fatal;
438 rc = shishi_tkt_build (tkt, serverkey);
439 if (rc != SHISHI_OK)
441 syslog (LOG_ERR, "shishi_tkt_build failed (%d): %s",
442 rc, shishi_strerror (rc));
443 goto fatal;
446 rc = shishi_as_rep_build (as, userkey);
447 if (rc != SHISHI_OK)
449 syslog (LOG_ERR, "shishi_as_rep_build failed (%d): %s",
450 rc, shishi_strerror (rc));
451 goto fatal;
454 if (arg.verbose_given)
456 shishi_kdcreq_print (handle, stderr, shishi_as_req (as));
457 shishi_encticketpart_print (handle, stderr,
458 shishi_tkt_encticketpart (tkt));
459 shishi_ticket_print (handle, stderr, shishi_tkt_ticket (tkt));
460 shishi_enckdcreppart_print (handle, stderr,
461 shishi_tkt_enckdcreppart (tkt));
462 shishi_kdcrep_print (handle, stderr, shishi_as_rep (as));
465 rc = SHISHI_OK;
467 fatal:
468 if (rc != SHISHI_OK)
469 syslog (LOG_ERR, "AS-REQ failed (%d): %s", rc, shishi_strerror (rc));
470 if (realm)
471 free (realm);
472 if (username)
473 free (username);
474 if (servername)
475 free (servername);
476 if (userkeys)
477 shisa_keys_free (dbh, userkeys, nuserkeys);
478 if (serverkeys)
479 shisa_keys_free (dbh, serverkeys, nserverkeys);
480 if (userkey)
481 shishi_key_done (userkey);
482 if (serverkey)
483 shishi_key_done (serverkey);
484 if (sessionkey)
485 shishi_key_done (sessionkey);
487 return rc;
490 static int
491 tgsreq1 (Shishi_tgs * tgs)
493 int rc;
494 Shishi_tkt *tkt;
495 Shishi_key *newsessionkey = NULL, *oldsessionkey = NULL;
496 Shishi_key *serverkey = NULL, *subkey = NULL, *tgkey = NULL;
497 char *servername = NULL, *serverrealm = NULL;
498 char *tgname = NULL, *tgrealm = NULL;
499 char *clientname = NULL, *clientrealm = NULL;
500 Shisa_principal krbtgt, server;
501 Shisa_key **tgkeys = NULL, **serverkeys = NULL;
502 size_t ntgkeys, nserverkeys;
504 rc = shishi_tgs_req_process (tgs);
505 if (rc != SHISHI_OK)
507 syslog (LOG_ERR, "shishi_tgs_req_process failed (%d): %s",
508 rc, shishi_strerror (rc));
509 goto fatal;
513 * The KRB_TGS_REQ message is processed in a manner similar to the
514 * KRB_AS_REQ message, but there are many additional checks to be
515 * performed. First, the Kerberos server MUST determine which server the
516 * accompanying ticket is for and it MUST select the appropriate key to
517 * decrypt it. For a normal KRB_TGS_REQ message, it will be for the
518 * ticket granting service, and the TGS's key will be used. If the TGT
519 * was issued by another realm, then the appropriate inter-realm key
520 * MUST be used. If the accompanying ticket is not a ticket-granting
521 * ticket for the current realm, but is for an application server in the
522 * current realm, the RENEW, VALIDATE, or PROXY options are specified in
523 * the request, and the server for which a ticket is requested is the
524 * server named in the accompanying ticket, then the KDC will decrypt
525 * the ticket in the authentication header using the key of the server
526 * for which it was issued. If no ticket can be found in the padata
527 * field, the KDC_ERR_PADATA_TYPE_NOSUPP error is returned.
530 /* Find name of ticket granter, e.g., krbtgt/JOSEFSSON.ORG@JOSEFSSON.ORG. */
532 rc = shishi_tkt_realm (shishi_ap_tkt (shishi_tgs_ap (tgs)), &tgrealm, NULL);
533 if (rc != SHISHI_OK)
535 syslog (LOG_ERR, "shishi_tkt_realm failed (%d): %s",
536 rc, shishi_strerror (rc));
537 goto fatal;
540 rc = shishi_tkt_server (shishi_ap_tkt (shishi_tgs_ap (tgs)), &tgname, NULL);
541 if (rc != SHISHI_OK)
543 syslog (LOG_ERR, "shishi_tkt_server failed (%d): %s",
544 rc, shishi_strerror (rc));
545 goto fatal;
548 syslog (LOG_DEBUG, "TGS-REQ uses ticket granter %s@%s", tgname, tgrealm);
550 rc = shisa_principal_find (dbh, tgrealm, tgname, &krbtgt);
551 if (rc != SHISA_OK && rc != SHISA_NO_PRINCIPAL)
553 syslog (LOG_ERR, "shisa_principal_find(%s@%s) failed (%d): %s",
554 tgname, tgrealm, rc, shisa_strerror (rc));
555 rc = SHISHI_INVALID_PRINCIPAL_NAME;
556 goto fatal;
558 if (rc == SHISA_NO_PRINCIPAL)
560 syslog (LOG_NOTICE, "TGS-REQ using %s@%s failed: no such tgt",
561 tgname, tgrealm);
562 rc = shishi_krberror_errorcode_set (handle, shishi_tgs_krberror (tgs),
563 SHISHI_KRB_AP_ERR_NOT_US);
564 if (rc != SHISHI_OK)
565 goto fatal;
566 rc = SHISHI_INVALID_PRINCIPAL_NAME;
567 goto fatal;
570 rc = shisa_keys_find (dbh, tgrealm, tgname, NULL, &tgkeys, &ntgkeys);
571 if (rc != SHISA_OK || ntgkeys == 0)
573 syslog (LOG_ERR, "shisa_keys_find(%s@%s) failed (%d): %s",
574 tgname, tgrealm, rc, shisa_strerror (rc));
575 rc = SHISHI_INVALID_PRINCIPAL_NAME;
576 goto fatal;
579 /* XXX use etype/kvno to select key. */
581 rc = shishi_key_from_value (handle, tgkeys[0]->etype,
582 tgkeys[0]->key, &tgkey);
583 if (rc != SHISHI_OK)
585 syslog (LOG_ERR, "shishi_key_from_value (tgt) failed (%d): %s",
586 rc, shishi_strerror (rc));
587 goto fatal;
590 rc = shishi_ap_req_process_keyusage
591 (shishi_tgs_ap (tgs), tgkey, SHISHI_KEYUSAGE_TGSREQ_APREQ_AUTHENTICATOR);
592 if (rc != SHISHI_OK)
594 syslog (LOG_ERR, "shishi_ap_req_process_keyusage failed (%d): %s",
595 rc, shishi_strerror (rc));
596 goto fatal;
600 * 3.3.3.1. Checking for revoked tickets
602 * Whenever a request is made to the ticket-granting server, the
603 * presented ticket(s) is(are) checked against a hot-list of tickets
604 * which have been canceled. This hot-list might be implemented by
605 * storing a range of issue timestamps for 'suspect tickets'; if a
606 * presented ticket had an authtime in that range, it would be rejected.
607 * In this way, a stolen ticket-granting ticket or renewable ticket
608 * cannot be used to gain additional tickets (renewals or otherwise)
609 * once the theft has been reported to the KDC for the realm in which
610 * the server resides. Any normal ticket obtained before it was reported
611 * stolen will still be valid (because they require no interaction with
612 * the KDC), but only until their normal expiration time. If TGT's have
613 * been issued for cross-realm authentication, use of the cross-realm
614 * TGT will not be affected unless the hot-list is propagated to the
615 * KDCs for the realms for which such cross-realm tickets were issued.
618 /* XXX Check if tgname@tgrealm is a valid TGT. */
621 * Once the accompanying ticket has been decrypted, the user-supplied
622 * checksum in the Authenticator MUST be verified against the contents
623 * of the request, and the message rejected if the checksums do not
624 * match (with an error code of KRB_AP_ERR_MODIFIED) or if the checksum
625 * is not collision-proof (with an error code of
626 * KRB_AP_ERR_INAPP_CKSUM). If the checksum type is not supported, the
627 * KDC_ERR_SUMTYPE_NOSUPP error is returned. If the authorization-data
628 * are present, they are decrypted using the sub-session key from the
629 * Authenticator.
631 * If any of the decryptions indicate failed integrity checks, the
632 * KRB_AP_ERR_BAD_INTEGRITY error is returned.
635 /* XXX check that checksum in authenticator match tgsreq.req-body */
637 syslog (LOG_DEBUG, "TGS-REQ authentication OK using %s@%s", tgname,
638 tgrealm);
641 * As discussed in section 3.1.2, the KDC MUST send a valid KRB_TGS_REP
642 * message if it receives a KRB_TGS_REQ message identical to one it has
643 * recently processed. However, if the authenticator is a replay, but
644 * the rest of the request is not identical, then the KDC SHOULD return
645 * KRB_AP_ERR_REPEAT.
648 /* XXX Do replay stuff. */
651 * The response will include a ticket for the requested server or for a
652 * ticket granting server of an intermediate KDC to be contacted to
653 * obtain the requested ticket. The Kerberos database is queried to
654 * retrieve the record for the appropriate server (including the key
655 * with which the ticket will be encrypted). If the request is for a
656 * ticket-granting ticket for a remote realm, and if no key is shared
657 * with the requested realm, then the Kerberos server will select the
658 * realm 'closest' to the requested realm with which it does share a
659 * key, and use that realm instead. Thss is theonly cases where the
660 * response for the KDC will be for a different server than that
661 * requested by the client.
664 rc = shishi_kdcreq_realm (handle, shishi_tgs_req (tgs), &serverrealm, NULL);
665 if (rc != SHISHI_OK)
667 syslog (LOG_ERR, "shishi_kdcreq_realm failed (%d): %s",
668 rc, shishi_strerror (rc));
669 goto fatal;
672 /* XXX Do cross-realm handling. */
674 rc = shishi_kdcreq_server (handle, shishi_tgs_req (tgs), &servername, NULL);
675 if (rc != SHISHI_OK)
677 syslog (LOG_ERR, "shishi_kdcreq_server failed (%d): %s",
678 rc, shishi_strerror (rc));
679 goto fatal;
682 rc = shisa_principal_find (dbh, serverrealm, servername, &server);
683 if (rc != SHISA_OK && rc != SHISA_NO_PRINCIPAL)
685 syslog (LOG_ERR, "shisa_principal_find(%s@%s) failed (%d): %s",
686 servername, serverrealm, rc, shisa_strerror (rc));
687 rc = SHISHI_INVALID_PRINCIPAL_NAME;
688 goto fatal;
690 if (rc == SHISA_NO_PRINCIPAL)
692 syslog (LOG_NOTICE, "TGS-REQ for %s@%s failed: no such server",
693 servername, serverrealm);
694 rc = shishi_krberror_errorcode_set (handle, shishi_tgs_krberror (tgs),
695 SHISHI_KDC_ERR_S_PRINCIPAL_UNKNOWN);
696 if (rc != SHISHI_OK)
697 goto fatal;
698 rc = SHISHI_INVALID_PRINCIPAL_NAME;
699 goto fatal;
702 rc = shisa_keys_find (dbh, serverrealm, servername, NULL,
703 &serverkeys, &nserverkeys);
704 if (rc != SHISA_OK || nserverkeys == 0)
706 syslog (LOG_ERR, "shisa_keys_find(%s@%s) failed (%d): %s",
707 servername, serverrealm, rc, shisa_strerror (rc));
708 rc = SHISHI_INVALID_PRINCIPAL_NAME;
709 goto fatal;
712 /* XXX Select "best" available key (highest kvno, best algorithm?)
713 here. The client etype should not influence this. */
714 rc = shishi_key_from_value (handle, serverkeys[0]->etype,
715 serverkeys[0]->key, &serverkey);
716 if (rc != SHISHI_OK)
718 syslog (LOG_ERR, "shisa_key_from_value (server) failed (%d): %s",
719 rc, shishi_strerror (rc));
720 goto fatal;
723 /* Generate session key for the newly generated ticket, of same key
724 type as the selected long-term server key. XXX let the client
725 influence the etype? think of AES only server and RFC 1510
726 client. if client etype is not used here, the client cannot talk
727 to the server. perhaps just as good though. */
729 rc = shishi_key_random (handle, shishi_key_type (serverkey),
730 &newsessionkey);
731 if (rc != SHISHI_OK)
733 syslog (LOG_ERR, "shishi_key_random failed (%d): %s",
734 rc, shishi_strerror (rc));
735 goto fatal;
739 * By default, the address field, the client's name and realm, the list
740 * of transited realms, the time of initial authentication, the
741 * expiration time, and the authorization data of the newly-issued
742 * ticket will be copied from the ticket-granting ticket (TGT) or
743 * renewable ticket. If the transited field needs to be updated, but the
744 * transited type is not supported, the KDC_ERR_TRTYPE_NOSUPP error is
745 * returned.
748 tkt = shishi_tgs_tkt (tgs);
749 if (tkt == NULL)
751 syslog (LOG_ERR, "shishi_tgs_tkt failed");
752 goto fatal;
755 rc = shishi_encticketpart_crealm
756 (handle, shishi_tkt_encticketpart (shishi_ap_tkt (shishi_tgs_ap (tgs))),
757 &clientrealm, NULL);
758 if (rc != SHISHI_OK)
760 syslog (LOG_ERR, "shishi_encticketpart_crealm failed (%d): %s",
761 rc, shishi_strerror (rc));
762 goto fatal;
765 rc = shishi_encticketpart_client
766 (handle, shishi_tkt_encticketpart (shishi_ap_tkt (shishi_tgs_ap (tgs))),
767 &clientname, NULL);
768 if (rc != SHISHI_OK)
770 syslog (LOG_ERR, "shishi_encticketpart_client failed (%d): %s",
771 rc, shishi_strerror (rc));
772 goto fatal;
775 rc = shishi_tkt_clientrealm_set (tkt, clientrealm, clientname);
776 if (rc != SHISHI_OK)
778 syslog (LOG_ERR, "shishi_tkt_clientrealm_set failed (%d): %s",
779 rc, shishi_strerror (rc));
780 goto fatal;
783 /* XXX Copy more fields. Move copying into lib/? */
785 rc = shishi_encticketpart_endtime_set
786 (handle, shishi_tkt_encticketpart (tkt),
787 shishi_generalize_time (handle,
788 shishi_kdcreq_tillc (handle,
789 shishi_tgs_req (tgs))));
790 if (rc != SHISHI_OK)
792 syslog (LOG_ERR, "shishi_encticketpart_endtime_set failed (%d): %s",
793 rc, shishi_strerror (rc));
794 goto fatal;
797 rc = shishi_tkt_key_set (tkt, newsessionkey);
798 if (rc != SHISHI_OK)
800 syslog (LOG_ERR, "shishi_tkt_key_set failed (%d): %s",
801 rc, shishi_strerror (rc));
802 goto fatal;
805 rc = shishi_tkt_serverrealm_set (tkt, serverrealm, servername);
806 if (rc != SHISHI_OK)
808 syslog (LOG_ERR, "shishi_tkt_serverrealm_set failed (%d): %s",
809 rc, shishi_strerror (rc));
810 goto fatal;
813 syslog (LOG_DEBUG, "TGS-REQ from %s@%s for %s@%s",
814 clientname, clientrealm, servername, serverrealm);
817 * If the request specifies an endtime, then the endtime of the new
818 * ticket is set to the minimum of (a) that request, (b) the endtime
819 * from the TGT, and (c) the starttime of the TGT plus the minimum of
820 * the maximum life for the application server and the maximum life for
821 * the local realm (the maximum life for the requesting principal was
822 * already applied when the TGT was issued). If the new ticket is to be
823 * a renewal, then the endtime above is replaced by the minimum of (a)
824 * the value of the renew_till field of the ticket and (b) the starttime
825 * for the new ticket plus the life (endtime-starttime) of the old
826 * ticket.
828 * If the FORWARDED option has been requested, then the resulting ticket
829 * will contain the addresses specified by the client. This option will
830 * only be honored if the FORWARDABLE flag is set in the TGT. The PROXY
831 * option is similar; the resulting ticket will contain the addresses
832 * specified by the client. It will be honored only if the PROXIABLE
833 * flag in the TGT is set. The PROXY option will not be honored on
834 * requests for additional ticket-granting tickets.
836 * If the requested start time is absent, indicates a time in the past,
837 * or is within the window of acceptable clock skew for the KDC and the
838 * POSTDATE option has not been specified, then the start time of the
839 * ticket is set to the authentication server's current time. If it
840 * indicates a time in the future beyond the acceptable clock skew, but
841 * the POSTDATED option has not been specified or the MAY-POSTDATE flag
842 * is not set in the TGT, then the error KDC_ERR_CANNOT_POSTDATE is
843 * returned. Otherwise, if the ticket-granting ticket has the MAY-
844 * POSTDATE flag set, then the resulting ticket will be postdated and
845 * the requested starttime is checked against the policy of the local
846 * realm. If acceptable, the ticket's start time is set as requested,
847 * and the INVALID flag is set. The postdated ticket MUST be validated
848 * before use by presenting it to the KDC after the starttime has been
849 * reached. However, in no case may the starttime, endtime, or renew-
850 * till time of a newly-issued postdated ticket extend beyond the renew-
851 * till time of the ticket-granting ticket.
853 * If the ENC-TKT-IN-SKEY option has been specified and an additional
854 * ticket has been included in the request, it indicates that the client
855 * is using user- to-user authentication to prove its identity to a
856 * server that does not have access to a persistent key. Section 3.7
857 * describes the affect of this option on the entire Kerberos protocol.
858 * When generating the KRB_TGS_REP message, this option in the
859 * KRB_TGS_REQ message tells the KDC to decrypt the additional ticket
860 * using the key for the server to which the additional ticket was
861 * issued and verify that it is a ticket-granting ticket. If the name of
862 * the requested server is missing from the request, the name of the
863 * client in the additional ticket will be used. Otherwise the name of
864 * the requested server will be compared to the name of the client in
865 * the additional ticket and if different, the request will be rejected.
866 * If the request succeeds, the session key from the additional ticket
867 * will be used to encrypt the new ticket that is issued instead of
868 * using the key of the server for which the new ticket will be used.
870 * If the name of the server in the ticket that is presented to the KDC
871 * as part of the authentication header is not that of the ticket-
872 * granting server itself, the server is registered in the realm of the
873 * KDC, and the RENEW option is requested, then the KDC will verify that
874 * the RENEWABLE flag is set in the ticket, that the INVALID flag is not
875 * set in the ticket, and that the renew_till time is still in the
876 * future. If the VALIDATE option is requested, the KDC will check that
877 * the starttime has passed and the INVALID flag is set. If the PROXY
878 * option is requested, then the KDC will check that the PROXIABLE flag
879 * is set in the ticket. If the tests succeed, and the ticket passes the
880 * hotlist check described in the next section, the KDC will issue the
881 * appropriate new ticket.
884 /* XXX Set more things in ticket, as described above. */
886 rc = shishi_tkt_build (tkt, serverkey);
887 if (rc != SHISHI_OK)
889 syslog (LOG_ERR, "shishi_tkt_build failed (%d): %s",
890 rc, shishi_strerror (rc));
891 goto fatal;
895 * The ciphertext part of the response in the KRB_TGS_REP message is
896 * encrypted in the sub-session key from the Authenticator, if present,
897 * or the session key from the ticket-granting ticket. It is not
898 * encrypted using the client's secret key. Furthermore, the client's
899 * key's expiration date and the key version number fields are left out
900 * since these values are stored along with the client's database
901 * record, and that record is not needed to satisfy a request based on a
902 * ticket-granting ticket.
905 rc = shishi_encticketpart_get_key
906 (handle, shishi_tkt_encticketpart (shishi_ap_tkt (shishi_tgs_ap (tgs))),
907 &oldsessionkey);
908 if (rc != SHISHI_OK)
910 syslog (LOG_ERR, "shishi_encticketpart_get_key failed (%d): %s",
911 rc, shishi_strerror (rc));
912 goto fatal;
915 rc = shishi_authenticator_get_subkey
916 (handle, shishi_ap_authenticator (shishi_tgs_ap (tgs)), &subkey);
917 if (rc != SHISHI_OK && rc != SHISHI_ASN1_NO_ELEMENT)
919 syslog (LOG_ERR, "shishi_authenticator_get_subkey failed (%d): %s",
920 rc, shishi_strerror (rc));
921 goto fatal;
924 if (rc == SHISHI_OK)
925 rc = shishi_tgs_rep_build
926 (tgs, SHISHI_KEYUSAGE_ENCTGSREPPART_AUTHENTICATOR_KEY, subkey);
927 else
928 rc = shishi_tgs_rep_build
929 (tgs, SHISHI_KEYUSAGE_ENCTGSREPPART_SESSION_KEY, oldsessionkey);
930 if (rc != SHISHI_OK)
932 syslog (LOG_ERR, "shishi_tgs_rep_build failed (%d): %s",
933 rc, shishi_strerror (rc));
934 goto fatal;
937 if (arg.verbose_given)
939 puts ("KDC-REQ in:");
940 shishi_kdcreq_print (handle, stderr, shishi_tgs_req (tgs));
941 puts ("AP-REQ in KDC-REQ:");
942 shishi_apreq_print (handle, stderr,
943 shishi_ap_req (shishi_tgs_ap (tgs)));
944 puts ("Authenticator in AP-REQ in KDC-REQ:");
945 shishi_authenticator_print (handle, stderr, shishi_ap_authenticator
946 (shishi_tgs_ap (tgs)));
947 puts ("Ticket in AP-REQ:");
948 shishi_ticket_print (handle, stdout,
949 shishi_tkt_ticket
950 (shishi_ap_tkt (shishi_tgs_ap (tgs))));
951 puts ("EncTicketPart in AP-REQ:");
952 shishi_encticketpart_print (handle, stdout,
953 shishi_tkt_encticketpart
954 (shishi_ap_tkt (shishi_tgs_ap (tgs))));
955 puts ("Ticket in TGS-REP:");
956 shishi_ticket_print (handle, stdout, shishi_tkt_ticket (tkt));
957 puts ("EncTicketPart in TGS-REP:");
958 shishi_encticketpart_print (handle, stderr,
959 shishi_tkt_encticketpart (tkt));
960 puts ("EncKDCRepPart in TGS-REP:");
961 shishi_enckdcreppart_print (handle, stderr,
962 shishi_tkt_enckdcreppart (tkt));
963 puts ("KDC-REP:");
964 shishi_kdcrep_print (handle, stderr, shishi_tgs_rep (tgs));
967 rc = SHISHI_OK;
969 fatal:
970 if (tgrealm)
971 free (tgrealm);
972 if (tgname)
973 free (tgname);
974 if (servername)
975 free (servername);
976 if (serverrealm)
977 free (serverrealm);
978 if (clientname)
979 free (clientname);
980 if (clientrealm)
981 free (clientrealm);
982 if (tgkeys)
983 shisa_keys_free (dbh, tgkeys, ntgkeys);
984 if (serverkeys)
985 shisa_keys_free (dbh, serverkeys, nserverkeys);
986 if (tgkey)
987 shishi_key_done (tgkey);
988 if (serverkey)
989 shishi_key_done (serverkey);
990 if (newsessionkey)
991 shishi_key_done (newsessionkey);
992 if (oldsessionkey)
993 shishi_key_done (oldsessionkey);
994 if (subkey)
995 shishi_key_done (subkey);
997 return rc;
1000 static int
1001 asreq (Shishi_asn1 kdcreq, char **out, size_t * outlen)
1003 Shishi_as *as;
1004 int rc;
1006 rc = shishi_as (handle, &as);
1007 if (rc != SHISHI_OK)
1009 syslog (LOG_ERR, "shishi_as failed (%d): %s", rc, shishi_strerror (rc));
1010 return rc;
1013 shishi_as_req_set (as, kdcreq);
1015 rc = asreq1 (as);
1016 if (rc != SHISHI_OK)
1018 syslog (LOG_NOTICE, "AS-REQ failing with KRB-ERROR: %s",
1019 shishi_krberror_message (handle, shishi_as_krberror (as)));
1020 rc = shishi_as_krberror_der (as, out, outlen);
1022 else
1023 rc = shishi_as_rep_der (as, out, outlen);
1024 if (rc != SHISHI_OK)
1026 syslog (LOG_ERR, "shishi_as_rep_der failed (%d): %s",
1027 rc, shishi_strerror (rc));
1028 return rc;
1031 return SHISHI_OK;
1034 static int
1035 tgsreq (Shishi_asn1 kdcreq, char **out, size_t * outlen)
1037 Shishi_tgs *tgs;
1038 int rc;
1040 rc = shishi_tgs (handle, &tgs);
1041 if (rc != SHISHI_OK)
1043 syslog (LOG_ERR, "shishi_tgs failed (%d): %s", rc,
1044 shishi_strerror (rc));
1045 return rc;
1048 shishi_tgs_req_set (tgs, kdcreq);
1050 rc = tgsreq1 (tgs);
1051 if (rc != SHISHI_OK)
1053 syslog (LOG_NOTICE, "TGS-REQ failing with KRB-ERROR: %s",
1054 shishi_krberror_message (handle, shishi_tgs_krberror (tgs)));
1055 rc = shishi_tgs_krberror_der (tgs, out, outlen);
1057 else
1058 rc = shishi_tgs_rep_der (tgs, out, outlen);
1059 if (rc != SHISHI_OK)
1061 syslog (LOG_ERR, "shishi_tgs_rep_der failed (%d): %s",
1062 rc, shishi_strerror (rc));
1063 return rc;
1066 return SHISHI_OK;
1069 ssize_t
1070 process (const char *in, size_t inlen, char **out)
1072 Shishi_asn1 node;
1073 size_t outlen;
1074 int rc;
1076 node = shishi_der2asn1 (handle, in, inlen);
1077 if (node == NULL)
1079 syslog (LOG_ERR, "Received %d bytes of unknown data", inlen);
1080 return -1;
1083 switch (shishi_asn1_msgtype (handle, node))
1085 case SHISHI_MSGTYPE_AS_REQ:
1086 syslog (LOG_ERR, "Trying AS-REQ");
1087 rc = asreq (node, out, &outlen);
1088 break;
1090 case SHISHI_MSGTYPE_TGS_REQ:
1091 syslog (LOG_ERR, "Trying TGS-REQ");
1092 rc = tgsreq (node, out, &outlen);
1093 break;
1095 default:
1096 syslog (LOG_ERR, "Unsupported KDC message type %d (0x%x)",
1097 shishi_asn1_msgtype (handle, node),
1098 shishi_asn1_msgtype (handle, node));
1099 rc = SHISHI_ASN1_ERROR;
1100 break;
1103 if (rc != SHISHI_OK)
1105 syslog (LOG_ERR, "Fatal error answering request (%d): %s",
1106 rc, shishi_strerror (rc));
1107 return -1;
1110 return outlen;