Fix messages.
[shishi.git] / lib / kdc.c
blob9fd93e65ef1c7e0f14e043ff4ef00c965db7462e
1 /* kdc.c Key distribution (AS/TGS) functions
2 * Copyright (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 /**
25 * shishi_as_derive_salt:
26 * @handle: shishi handle as allocated by shishi_init().
27 * @asreq: input AS-REQ variable.
28 * @asrep: input AS-REP variable.
29 * @salt: output array with salt.
30 * @saltlen: on input, maximum size of output array with salt, on output,
31 * holds actual size of output array with salt.
33 * Derive the salt that should be used when deriving a key via
34 * shishi_string_to_key() for an AS exchange. Currently this searches
35 * for PA-DATA of type SHISHI_PA_PW_SALT in the AS-REP and returns it
36 * if found, otherwise the salt is derived from the client name and
37 * realm in AS-REQ.
39 * Return value: Returns SHISHI_OK iff successful.
40 **/
41 int
42 shishi_as_derive_salt (Shishi * handle,
43 Shishi_asn1 asreq,
44 Shishi_asn1 asrep, char *salt, size_t * saltlen)
46 size_t len = *saltlen;
47 size_t tmplen;
48 char *format;
49 int res;
50 int i, n;
52 res = shishi_asn1_number_of_elements (handle, asrep, "padata", &n);
53 if (res == SHISHI_ASN1_NO_ELEMENT)
54 n = 0;
55 else if (res != SHISHI_OK)
56 return res;
58 for (i = 1; i <= n; i++)
60 int patype;
62 asprintf (&format, "padata.?%d.padata-type", i);
63 res = shishi_asn1_read_int32 (handle, asrep, format, &patype);
64 free (format);
65 if (res != SHISHI_OK)
66 return res;
68 if (patype == SHISHI_PA_PW_SALT)
70 asprintf (&format, "padata.?%d.padata-value", i);
71 res = shishi_asn1_read (handle, asrep, format, salt, saltlen);
72 free (format);
73 if (res != SHISHI_OK)
74 return res;
76 return SHISHI_OK;
80 len = *saltlen;
81 res = shishi_asn1_read (handle, asreq, "req-body.realm", salt, &len);
82 if (res != SHISHI_OK)
83 return res;
85 res = shishi_asn1_number_of_elements (handle, asreq,
86 "req-body.cname.name-string", &n);
87 if (res != SHISHI_OK)
88 return res;
90 for (i = 1; i <= n; i++)
92 if (*saltlen < len)
93 return SHISHI_TOO_SMALL_BUFFER;
94 tmplen = *saltlen - len;
96 asprintf (&format, "req-body.cname.name-string.?%d", i);
97 res = shishi_asn1_read (handle, asreq, format, salt + len, &tmplen);
98 free (format);
99 if (res != SHISHI_OK)
100 return res;
102 len += tmplen;
105 *saltlen = len;
107 return SHISHI_OK;
111 shishi_kdcreq_sendrecv (Shishi * handle, Shishi_asn1 kdcreq,
112 Shishi_asn1 * kdcrep)
114 char *der;
115 size_t der_len;
116 size_t buflen;
117 char *buffer;
118 char *realm;
119 size_t realmlen;
120 int res;
122 res = shishi_new_a2d (handle, kdcreq, &der, &der_len);
123 if (res != SHISHI_OK)
125 shishi_error_printf (handle, "Could not DER encode AS-REQ: %s\n",
126 shishi_strerror (res));
127 return res;
130 res = shishi_asn1_read2 (handle, kdcreq, "req-body.realm",
131 &realm, &realmlen);
132 if (res != SHISHI_OK)
134 shishi_error_printf (handle, "Could not get realm: %s\n",
135 shishi_error (handle));
136 return res;
138 realm = xrealloc (realm, realmlen + 1);
139 realm[realmlen] = '\0';
141 res = shishi_kdc_sendrecv (handle, realm, der, der_len, &buffer, &buflen);
142 if (res != SHISHI_OK)
144 shishi_error_printf (handle, "Could not send to KDC: %s\n",
145 shishi_error (handle));
146 return res;
148 free (realm);
149 free (der);
151 if (VERBOSEASN1 (handle))
152 printf ("received %d bytes\n", buflen);
154 *kdcrep = shishi_der2asn1_asrep (handle, buffer, buflen);
155 if (*kdcrep == NULL)
157 *kdcrep = shishi_der2asn1_tgsrep (handle, buffer, buflen);
158 if (*kdcrep == NULL)
160 *kdcrep = shishi_der2asn1_kdcrep (handle, buffer, buflen);
161 if (*kdcrep == NULL)
163 *kdcrep = shishi_der2asn1_krberror (handle, buffer, buflen);
164 if (*kdcrep == NULL)
166 shishi_error_printf
167 (handle, "Could not DER decode AS-REP/KRB-ERROR: %s",
168 shishi_error (handle));
169 return SHISHI_ASN1_ERROR;
172 shishi_error_clear (handle);
173 return SHISHI_GOT_KRBERROR;
175 else
177 printf
178 ("Buggy server replied with KDC-REP instead of AS-REP\n");
182 free (buffer);
184 return SHISHI_OK;
188 * shishi_kdc_copy_crealm:
189 * @handle: shishi handle as allocated by shishi_init().
190 * @kdcrep: KDC-REP to read crealm from.
191 * @encticketpart: EncTicketPart to set crealm in.
193 * Set crealm in KDC-REP to value in EncTicketPart.
195 * Return value: Returns SHISHI_OK if successful.
198 shishi_kdc_copy_crealm (Shishi * handle,
199 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
201 char *buf;
202 size_t buflen;
203 int res;
205 #if 0
206 buf[0] = '\0'; /* XXX if crealm is empty, buflen == 0 which
207 causes libtasn1 to strlen(buf)... */
208 #endif
209 res = shishi_asn1_read2 (handle, encticketpart, "crealm", &buf, &buflen);
210 if (res != SHISHI_OK)
211 return res;
213 res = shishi_asn1_write (handle, kdcrep, "crealm", buf, buflen);
214 free (buf);
215 if (res != SHISHI_OK)
216 return res;
218 return SHISHI_OK;
222 * shishi_as_check_crealm:
223 * @handle: shishi handle as allocated by shishi_init().
224 * @asreq: AS-REQ to compare realm field in.
225 * @asrep: AS-REP to compare realm field in.
227 * Verify that AS-REQ.req-body.realm and AS-REP.crealm fields matches.
228 * This is one of the steps that has to be performed when processing a
229 * AS-REQ and AS-REP exchange, see shishi_kdc_process().
231 * Return value: Returns SHISHI_OK if successful,
232 * SHISHI_REALM_MISMATCH if the values differ, or an error code.
235 shishi_as_check_crealm (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
237 char *reqrealm, *reprealm;
238 size_t reqrealmlen, reprealmlen;
239 int res;
241 res = shishi_asn1_read2 (handle, asreq, "req-body.realm",
242 &reqrealm, &reqrealmlen);
243 if (res != SHISHI_OK)
245 shishi_error_printf (handle, "Could not read request realm: %s\n",
246 shishi_strerror (res));
247 return res;
250 res = shishi_asn1_read2 (handle, asrep, "crealm", &reprealm, &reprealmlen);
251 if (res != SHISHI_OK)
253 shishi_error_printf (handle, "Could not read reply realm: %s\n",
254 shishi_strerror (res));
255 return res;
258 reqrealm[reqrealmlen] = '\0';
259 reprealm[reprealmlen] = '\0';
261 if (VERBOSEASN1 (handle))
263 printf ("request realm: %s\n", reqrealm);
264 printf ("reply realm: %s\n", reprealm);
267 res = strcmp (reqrealm, reprealm) != 0;
269 free (reqrealm);
270 free (reprealm);
272 if (res)
273 return SHISHI_REALM_MISMATCH;
275 return SHISHI_OK;
279 * shishi_kdc_copy_cname:
280 * @handle: shishi handle as allocated by shishi_init().
281 * @kdcrep: KDC-REQ to read cname from.
282 * @encticketpart: EncTicketPart to set cname in.
284 * Set cname in KDC-REP to value in EncTicketPart.
286 * Return value: Returns SHISHI_OK if successful.
289 shishi_kdc_copy_cname (Shishi * handle,
290 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
292 char *buf;
293 char *format;
294 size_t buflen;
295 int res;
296 int i, n;
298 res = shishi_asn1_read2 (handle, encticketpart,
299 "cname.name-type", &buf, &buflen);
300 if (res != SHISHI_OK)
301 return res;
303 res = shishi_asn1_write (handle, kdcrep, "cname.name-type", buf, buflen);
304 free (buf);
305 if (res != SHISHI_OK)
306 return res;
308 res = shishi_asn1_number_of_elements (handle, encticketpart,
309 "cname.name-string", &n);
310 if (res != SHISHI_OK)
311 return res;
313 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", NULL, 0);
314 if (res != SHISHI_OK)
315 return res;
317 for (i = 1; i <= n; i++)
319 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", "NEW", 1);
320 if (res != SHISHI_OK)
321 return res;
323 asprintf (&format, "cname.name-string.?%d", i);
324 res = shishi_asn1_read2 (handle, encticketpart, format, &buf, &buflen);
325 free (format);
326 if (res != SHISHI_OK)
327 return res;
329 asprintf (&format, "cname.name-string.?%d", i);
330 res = shishi_asn1_write (handle, kdcrep, format, buf, buflen);
331 free (format);
332 free (buf);
333 if (res != SHISHI_OK)
334 return res;
337 return SHISHI_OK;
341 * shishi_as_check_cname:
342 * @handle: shishi handle as allocated by shishi_init().
343 * @asreq: AS-REQ to compare client name field in.
344 * @asrep: AS-REP to compare client name field in.
346 * Verify that AS-REQ.req-body.realm and AS-REP.crealm fields matches.
347 * This is one of the steps that has to be performed when processing a
348 * AS-REQ and AS-REP exchange, see shishi_kdc_process().
350 * Return value: Returns SHISHI_OK if successful,
351 * SHISHI_CNAME_MISMATCH if the values differ, or an error code.
354 shishi_as_check_cname (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
356 char *reqcname, *repcname;
357 size_t reqcnamelen, repcnamelen;
358 char *format;
359 int res;
360 int i, j;
362 /* We do not compare msg-type as recommended on the ietf-krb-wg list */
364 res = shishi_asn1_number_of_elements (handle, asreq,
365 "req-body.cname.name-string", &i);
366 if (res != SHISHI_OK)
367 return res;
369 res = shishi_asn1_number_of_elements (handle, asrep,
370 "cname.name-string", &j);
371 if (res != SHISHI_OK)
372 return res;
374 if (i != j)
375 return SHISHI_CNAME_MISMATCH;
377 for (i = 1; i <= j; i++)
379 asprintf (&format, "req-body.cname.name-string.?%d", i);
380 res =
381 shishi_asn1_read2 (handle, asreq, format, &reqcname, &reqcnamelen);
382 free (format);
383 if (res != SHISHI_OK)
384 return res;
386 asprintf (&format, "cname.name-string.?%d", i);
387 res =
388 shishi_asn1_read2 (handle, asrep, format, &repcname, &repcnamelen);
389 free (format);
390 if (res != SHISHI_OK)
391 return res;
393 if (VERBOSEASN1 (handle))
395 reqcname[reqcnamelen] = '\0';
396 repcname[repcnamelen] = '\0';
397 printf ("request cname %d: %s\n", i, reqcname);
398 printf ("reply cname %d: %s\n", i, repcname);
401 res = (reqcnamelen != repcnamelen) ||
402 (memcmp (reqcname, repcname, reqcnamelen) != 0);
404 free (reqcname);
405 free (repcname);
407 if (res)
408 return SHISHI_CNAME_MISMATCH;
411 return SHISHI_OK;
415 * shishi_kdc_copy_nonce:
416 * @handle: shishi handle as allocated by shishi_init().
417 * @kdcreq: KDC-REQ to read nonce from.
418 * @enckdcreppart: EncKDCRepPart to set nonce in.
420 * Set nonce in EncKDCRepPart to value in KDC-REQ.
422 * Return value: Returns SHISHI_OK if successful.
425 shishi_kdc_copy_nonce (Shishi * handle,
426 Shishi_asn1 kdcreq, Shishi_asn1 enckdcreppart)
428 int res;
429 uint32_t nonce;
431 res = shishi_kdcreq_nonce (handle, kdcreq, &nonce);
432 if (res != SHISHI_OK)
433 return res;
435 res = shishi_enckdcreppart_nonce_set (handle, enckdcreppart, nonce);
436 if (res != SHISHI_OK)
437 return res;
439 return SHISHI_OK;
442 static int
443 shishi_kdc_check_nonce_1 (Shishi * handle,
444 char *reqnonce, size_t reqnoncelen,
445 char *repnonce, size_t repnoncelen)
447 if (VERBOSENOICE (handle))
449 size_t i;
451 printf ("request nonce (len=%d) ", reqnoncelen);
452 for (i = 0; i < reqnoncelen; i++)
453 printf ("%02x", reqnonce[i] & 0xFF);
454 printf ("\n");
455 printf ("reply nonce (len=%d) ", repnoncelen);
456 for (i = 0; i < repnoncelen; i++)
457 printf ("%02x", repnonce[i] & 0xFF);
458 printf ("\n");
461 if (reqnoncelen > 4 && repnoncelen == 4)
463 /* This case warrants some explanation.
465 * RFC 1510 didn't restrict nonce to 4 bytes, so the nonce field
466 * may be longer. There are KDCs that will accept longer nonces
467 * but truncated them to 4 bytes in the response. If we happen
468 * to parse such a KDC request, we consider it OK even though it
469 * isn't. I doubt this is a security problem, because you need
470 * to break the integrity protection of the encryption system
471 * as well as guess the nonce correctly. The nonce doesn't seem
472 * to serve any purpose at all, really.
476 if (memcmp (reqnonce + reqnoncelen - 4, repnonce, 4) != 0)
477 return SHISHI_NONCE_MISMATCH;
479 shishi_warn (handle, "server truncated long nonce to 4 bytes");
481 return SHISHI_OK;
484 if (reqnoncelen != repnoncelen ||
485 memcmp (reqnonce, repnonce, repnoncelen) != 0)
486 return SHISHI_NONCE_MISMATCH;
488 return SHISHI_OK;
492 * shishi_kdc_check_nonce:
493 * @handle: shishi handle as allocated by shishi_init().
494 * @kdcreq: KDC-REQ to compare nonce field in.
495 * @enckdcreppart: Encrypted KDC-REP part to compare nonce field in.
497 * Verify that KDC-REQ.req-body.nonce and EncKDCRepPart.nonce fields
498 * matches. This is one of the steps that has to be performed when
499 * processing a KDC-REQ and KDC-REP exchange.
501 * Return value: Returns SHISHI_OK if successful,
502 * SHISHI_NONCE_LENGTH_MISMATCH if the nonces have different lengths
503 * (usually indicates that buggy server truncated nonce to 4 bytes),
504 * SHISHI_NONCE_MISMATCH if the values differ, or an error code.
507 shishi_kdc_check_nonce (Shishi * handle,
508 Shishi_asn1 kdcreq, Shishi_asn1 enckdcreppart)
510 char *reqnonce;
511 char *repnonce;
512 size_t reqnoncelen, repnoncelen;
513 int res;
515 res = shishi_asn1_read2 (handle, kdcreq, "req-body.nonce",
516 &reqnonce, &reqnoncelen);
517 if (res != SHISHI_OK)
519 shishi_error_printf (handle, "Could not read request nonce: %s\n",
520 shishi_strerror (res));
521 return res;
524 res = shishi_asn1_read2 (handle, enckdcreppart, "nonce",
525 &repnonce, &repnoncelen);
526 if (res != SHISHI_OK)
528 free (reqnonce);
529 shishi_error_printf (handle, "Could not read reply nonce: %s\n",
530 shishi_strerror (res));
531 return res;
534 res = shishi_kdc_check_nonce_1 (handle, reqnonce, reqnoncelen,
535 repnonce, repnoncelen);
537 free (reqnonce);
538 free (repnonce);
540 return res;
544 * shishi_tgs_process:
545 * @handle: shishi handle as allocated by shishi_init().
546 * @tgsreq: input variable that holds the sent KDC-REQ.
547 * @tgsrep: input variable that holds the received KDC-REP.
548 * @authenticator: input variable with Authenticator from AP-REQ in KDC-REQ.
549 * @oldenckdcreppart: input variable with EncKDCRepPart used in request.
550 * @enckdcreppart: output variable that holds new EncKDCRepPart.
552 * Process a TGS client exchange and output decrypted EncKDCRepPart
553 * which holds details for the new ticket received. This function
554 * simply derives the encryption key from the ticket used to construct
555 * the TGS request and calls shishi_kdc_process(), which see.
557 * Return value: Returns SHISHI_OK iff the TGS client exchange was
558 * successful.
561 shishi_tgs_process (Shishi * handle,
562 Shishi_asn1 tgsreq,
563 Shishi_asn1 tgsrep,
564 Shishi_asn1 authenticator,
565 Shishi_asn1 oldenckdcreppart, Shishi_asn1 * enckdcreppart)
567 Shishi_key *tktkey;
568 Shishi_key *subkey;
569 int use_subkey;
570 int etype;
571 int res;
573 res = shishi_kdcrep_get_enc_part_etype (handle, tgsrep, &etype);
574 if (res != SHISHI_OK)
575 return res;
577 res = shishi_authenticator_get_subkey (handle, authenticator, &subkey);
578 use_subkey = (res != SHISHI_ASN1_NO_ELEMENT);
579 if (res != SHISHI_OK && res != SHISHI_ASN1_NO_ELEMENT)
580 return res;
582 res = shishi_enckdcreppart_get_key (handle, oldenckdcreppart, &tktkey);
583 if (res != SHISHI_OK)
584 return res;
586 if (etype != shishi_key_type (use_subkey ? subkey : tktkey))
587 res = SHISHI_TGSREP_BAD_KEYTYPE;
588 else
589 res = shishi_kdc_process (handle, tgsreq, tgsrep,
590 use_subkey ? subkey : tktkey,
591 use_subkey ?
592 SHISHI_KEYUSAGE_ENCTGSREPPART_AUTHENTICATOR_KEY
593 : SHISHI_KEYUSAGE_ENCTGSREPPART_SESSION_KEY,
594 enckdcreppart);
596 /* Entire if statement to work around buggy KDCs. */
597 if (use_subkey && (res == SHISHI_CRYPTO_ERROR ||
598 res == SHISHI_TGSREP_BAD_KEYTYPE))
600 int tmpres;
602 /* Try again using key from ticket instead of subkey */
603 if (etype != shishi_key_type (tktkey))
604 tmpres = SHISHI_TGSREP_BAD_KEYTYPE;
605 else
606 tmpres = shishi_kdc_process (handle, tgsreq, tgsrep, tktkey,
607 SHISHI_KEYUSAGE_ENCTGSREPPART_SESSION_KEY,
608 enckdcreppart);
610 /* if bug workaround code didn't help, return original error. */
611 if (tmpres != SHISHI_OK)
612 return res;
614 shishi_warn (handle, "KDC bug: Reply encrypted using wrong key.");
616 res = tmpres;
619 if (res != SHISHI_OK)
620 return res;
622 return SHISHI_OK;
626 * shishi_as_process:
627 * @handle: shishi handle as allocated by shishi_init().
628 * @asreq: input variable that holds the sent KDC-REQ.
629 * @asrep: input variable that holds the received KDC-REP.
630 * @string: input variable with zero terminated password.
631 * @enckdcreppart: output variable that holds new EncKDCRepPart.
633 * Process an AS client exchange and output decrypted EncKDCRepPart
634 * which holds details for the new ticket received. This function
635 * simply derives the encryption key from the password and calls
636 * shishi_kdc_process(), which see.
638 * Return value: Returns SHISHI_OK iff the AS client exchange was
639 * successful.
642 shishi_as_process (Shishi * handle,
643 Shishi_asn1 asreq,
644 Shishi_asn1 asrep,
645 const char *string, Shishi_asn1 * enckdcreppart)
647 unsigned char salt[BUFSIZ];
648 size_t saltlen;
649 int res;
650 Shishi_key *key;
651 int keytype;
653 saltlen = sizeof (salt);
654 res = shishi_as_derive_salt (handle, asreq, asrep, salt, &saltlen);
655 if (res != SHISHI_OK)
656 return res;
658 res = shishi_kdcrep_get_enc_part_etype (handle, asrep, &keytype);
659 if (res != SHISHI_OK)
660 return res;
662 res = shishi_key_from_string (handle, keytype,
663 string, strlen (string),
664 salt, saltlen, NULL, &key);
665 if (res != SHISHI_OK)
666 return res;
668 if (VERBOSENOICE (handle))
669 shishi_key_print (handle, stderr, key);
671 res = shishi_kdc_process (handle, asreq, asrep, key,
672 SHISHI_KEYUSAGE_ENCASREPPART, enckdcreppart);
674 return res;
678 * shishi_kdc_process:
679 * @handle: shishi handle as allocated by shishi_init().
680 * @kdcreq: input variable that holds the sent KDC-REQ.
681 * @kdcrep: input variable that holds the received KDC-REP.
682 * @key: input array with key to decrypt encrypted part of KDC-REP with.
683 * @keyusage: kereros key usage value.
684 * @enckdcreppart: output variable that holds new EncKDCRepPart.
686 * Process a KDC client exchange and output decrypted EncKDCRepPart
687 * which holds details for the new ticket received. Use
688 * shishi_kdcrep_get_ticket() to extract the ticket. This function
689 * verifies the various conditions that must hold if the response is
690 * to be considered valid, specifically it compares nonces
691 * (shishi_check_nonces()) and if the exchange was a AS exchange, it
692 * also compares cname and crealm (shishi_check_cname() and
693 * shishi_check_crealm()).
695 * Usually the shishi_as_process() and shishi_tgs_process() functions
696 * should be used instead, since they simplify the decryption key
697 * computation.
699 * Return value: Returns SHISHI_OK iff the KDC client exchange was
700 * successful.
703 shishi_kdc_process (Shishi * handle,
704 Shishi_asn1 kdcreq,
705 Shishi_asn1 kdcrep,
706 Shishi_key * key, int keyusage,
707 Shishi_asn1 * enckdcreppart)
709 int res;
710 int msgtype;
713 If the reply message type is KRB_AS_REP, then the client verifies
714 that the cname and crealm fields in the cleartext portion of the
715 reply match what it requested. If any padata fields are present,
716 they may be used to derive the proper secret key to decrypt the
717 message. The client decrypts the encrypted part of the response
718 using its secret key, verifies that the nonce in the encrypted
719 part matches the nonce it supplied in its request (to detect
720 replays). It also verifies that the sname and srealm in the
721 response match those in the request (or are otherwise expected
722 values), and that the host address field is also correct. It then
723 stores the ticket, session key, start and expiration times, and
724 other information for later use. The key-expiration field from the
725 encrypted part of the response may be checked to notify the user
726 of impending key expiration (the client program could then suggest
727 remedial action, such as a password change).
730 msgtype = 0;
731 res = shishi_asn1_read_integer (handle, kdcrep, "msg-type", &msgtype);
732 if (res != SHISHI_OK)
733 return res;
735 if (msgtype == SHISHI_MSGTYPE_AS_REP)
737 res = shishi_as_check_crealm (handle, kdcreq, kdcrep);
738 if (res != SHISHI_OK)
739 return res;
741 res = shishi_as_check_cname (handle, kdcreq, kdcrep);
742 if (res != SHISHI_OK)
743 return res;
746 res = shishi_kdcrep_decrypt (handle, kdcrep, key, keyusage, enckdcreppart);
747 if (res != SHISHI_OK)
748 return res;
750 res = shishi_kdc_check_nonce (handle, kdcreq, *enckdcreppart);
751 if (res != SHISHI_OK)
752 return res;
754 return SHISHI_OK;