Add.
[shishi.git] / lib / kdc.c
blob6b8b17aac98932d911e95bf3b33d682a4da64703
1 /* kdc.c --- Key distribution (AS/TGS) functions.
2 * Copyright (C) 2002, 2003, 2004, 2007 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * Shishi is distributed in the hope that it will be useful, but
12 * 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, see http://www.gnu.org/licenses or write
18 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 * Floor, Boston, MA 02110-1301, USA
23 #include "internal.h"
25 /**
26 * shishi_as_derive_salt:
27 * @handle: shishi handle as allocated by shishi_init().
28 * @asreq: input AS-REQ variable.
29 * @asrep: input AS-REP variable.
30 * @salt: newly allocated output array with salt.
31 * @saltlen: 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 i, n;
47 char *format;
48 int res;
50 res = shishi_asn1_number_of_elements (handle, asrep, "padata", &n);
51 if (res == SHISHI_ASN1_NO_ELEMENT)
52 n = 0;
53 else if (res != SHISHI_OK)
54 return res;
56 for (i = 1; i <= n; i++)
58 int patype;
60 asprintf (&format, "padata.?%d.padata-type", i);
61 res = shishi_asn1_read_int32 (handle, asrep, format, &patype);
62 free (format);
63 if (res != SHISHI_OK)
64 return res;
66 if (patype == SHISHI_PA_PW_SALT)
68 asprintf (&format, "padata.?%d.padata-value", i);
69 res = shishi_asn1_read (handle, asrep, format, salt, saltlen);
70 free (format);
71 if (res != SHISHI_OK)
72 return res;
74 return SHISHI_OK;
78 res = shishi_kdcreq_realm (handle, asreq, salt, saltlen);
79 if (res != SHISHI_OK)
80 return res;
82 res = shishi_asn1_number_of_elements (handle, asreq,
83 "req-body.cname.name-string", &n);
84 if (res != SHISHI_OK)
85 return res;
87 for (i = 1; i <= n; i++)
89 char *tmp;
90 size_t tmplen;
92 asprintf (&format, "req-body.cname.name-string.?%d", i);
93 res = shishi_asn1_read (handle, asreq, format, &tmp, &tmplen);
94 free (format);
95 if (res != SHISHI_OK)
96 return res;
98 *saltlen += tmplen;
100 *salt = xrealloc (*salt, *saltlen + 1);
101 memcpy (*salt + *saltlen - tmplen, tmp, tmplen);
102 (*salt)[*saltlen] = '\0';
103 free (tmp);
106 return SHISHI_OK;
110 shishi_kdcreq_sendrecv_hint (Shishi * handle,
111 Shishi_asn1 kdcreq,
112 Shishi_asn1 * kdcrep, Shishi_tkts_hint * hint)
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_asn1_to_der (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_read (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_hint (handle, realm, der, der_len,
142 &buffer, &buflen, hint);
143 if (res != SHISHI_OK)
145 shishi_error_printf (handle, "Could not send to KDC: %s\n",
146 shishi_error (handle));
147 return res;
149 free (realm);
150 free (der);
152 if (VERBOSEASN1 (handle))
153 printf ("received %d bytes\n", buflen);
155 *kdcrep = shishi_der2asn1_asrep (handle, buffer, buflen);
156 if (*kdcrep == NULL)
158 *kdcrep = shishi_der2asn1_tgsrep (handle, buffer, buflen);
159 if (*kdcrep == NULL)
161 *kdcrep = shishi_der2asn1_kdcrep (handle, buffer, buflen);
162 if (*kdcrep == NULL)
164 *kdcrep = shishi_der2asn1_krberror (handle, buffer, buflen);
165 if (*kdcrep == NULL)
167 shishi_error_printf
168 (handle, "Could not DER decode AS-REP/KRB-ERROR: %s",
169 shishi_error (handle));
170 return SHISHI_ASN1_ERROR;
173 shishi_error_clear (handle);
174 return SHISHI_GOT_KRBERROR;
176 else
178 printf
179 ("Buggy server replied with KDC-REP instead of AS-REP\n");
183 free (buffer);
185 return SHISHI_OK;
189 shishi_kdcreq_sendrecv (Shishi * handle, Shishi_asn1 kdcreq,
190 Shishi_asn1 * kdcrep)
192 return shishi_kdcreq_sendrecv_hint (handle, kdcreq, kdcrep, NULL);
196 * shishi_kdc_copy_crealm:
197 * @handle: shishi handle as allocated by shishi_init().
198 * @kdcrep: KDC-REP to read crealm from.
199 * @encticketpart: EncTicketPart to set crealm in.
201 * Set crealm in KDC-REP to value in EncTicketPart.
203 * Return value: Returns SHISHI_OK if successful.
206 shishi_kdc_copy_crealm (Shishi * handle,
207 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
209 char *buf;
210 size_t buflen;
211 int res;
213 res = shishi_asn1_read (handle, encticketpart, "crealm", &buf, &buflen);
214 if (res != SHISHI_OK)
215 return res;
217 res = shishi_asn1_write (handle, kdcrep, "crealm", buf, buflen);
218 free (buf);
219 if (res != SHISHI_OK)
220 return res;
222 return SHISHI_OK;
226 * shishi_as_check_crealm:
227 * @handle: shishi handle as allocated by shishi_init().
228 * @asreq: AS-REQ to compare realm field in.
229 * @asrep: AS-REP to compare realm field in.
231 * Verify that AS-REQ.req-body.realm and AS-REP.crealm fields matches.
232 * This is one of the steps that has to be performed when processing a
233 * AS-REQ and AS-REP exchange, see shishi_kdc_process().
235 * Return value: Returns SHISHI_OK if successful,
236 * SHISHI_REALM_MISMATCH if the values differ, or an error code.
239 shishi_as_check_crealm (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
241 char *reqrealm, *reprealm;
242 size_t reqrealmlen, reprealmlen;
243 int res;
245 res = shishi_asn1_read (handle, asreq, "req-body.realm",
246 &reqrealm, &reqrealmlen);
247 if (res != SHISHI_OK)
249 shishi_error_printf (handle, "Could not read request realm: %s\n",
250 shishi_strerror (res));
251 return res;
254 res = shishi_asn1_read (handle, asrep, "crealm", &reprealm, &reprealmlen);
255 if (res != SHISHI_OK)
257 shishi_error_printf (handle, "Could not read reply realm: %s\n",
258 shishi_strerror (res));
259 return res;
262 reqrealm[reqrealmlen] = '\0';
263 reprealm[reprealmlen] = '\0';
265 if (VERBOSEASN1 (handle))
267 printf ("request realm: %s\n", reqrealm);
268 printf ("reply realm: %s\n", reprealm);
271 res = strcmp (reqrealm, reprealm) != 0;
273 free (reqrealm);
274 free (reprealm);
276 if (res)
277 return SHISHI_REALM_MISMATCH;
279 return SHISHI_OK;
283 * shishi_kdc_copy_cname:
284 * @handle: shishi handle as allocated by shishi_init().
285 * @kdcrep: KDC-REQ to read cname from.
286 * @encticketpart: EncTicketPart to set cname in.
288 * Set cname in KDC-REP to value in EncTicketPart.
290 * Return value: Returns SHISHI_OK if successful.
293 shishi_kdc_copy_cname (Shishi * handle,
294 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
296 char *buf;
297 char *format;
298 size_t buflen, i, n;
299 int res;
301 res = shishi_asn1_read (handle, encticketpart,
302 "cname.name-type", &buf, &buflen);
303 if (res != SHISHI_OK)
304 return res;
306 res = shishi_asn1_write (handle, kdcrep, "cname.name-type", buf, buflen);
307 free (buf);
308 if (res != SHISHI_OK)
309 return res;
311 res = shishi_asn1_number_of_elements (handle, encticketpart,
312 "cname.name-string", &n);
313 if (res != SHISHI_OK)
314 return res;
316 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", NULL, 0);
317 if (res != SHISHI_OK)
318 return res;
320 for (i = 1; i <= n; i++)
322 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", "NEW", 1);
323 if (res != SHISHI_OK)
324 return res;
326 asprintf (&format, "cname.name-string.?%d", i);
327 res = shishi_asn1_read (handle, encticketpart, format, &buf, &buflen);
328 free (format);
329 if (res != SHISHI_OK)
330 return res;
332 asprintf (&format, "cname.name-string.?%d", i);
333 res = shishi_asn1_write (handle, kdcrep, format, buf, buflen);
334 free (format);
335 free (buf);
336 if (res != SHISHI_OK)
337 return res;
340 return SHISHI_OK;
344 * shishi_as_check_cname:
345 * @handle: shishi handle as allocated by shishi_init().
346 * @asreq: AS-REQ to compare client name field in.
347 * @asrep: AS-REP to compare client name field in.
349 * Verify that AS-REQ.req-body.realm and AS-REP.crealm fields matches.
350 * This is one of the steps that has to be performed when processing a
351 * AS-REQ and AS-REP exchange, see shishi_kdc_process().
353 * Return value: Returns SHISHI_OK if successful,
354 * SHISHI_CNAME_MISMATCH if the values differ, or an error code.
357 shishi_as_check_cname (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
359 char *reqcname, *repcname;
360 size_t reqcnamelen, repcnamelen, i, j;
361 char *format;
362 int res;
364 /* We do not compare msg-type as recommended on the ietf-krb-wg list */
366 res = shishi_asn1_number_of_elements (handle, asreq,
367 "req-body.cname.name-string", &i);
368 if (res != SHISHI_OK)
369 return res;
371 res = shishi_asn1_number_of_elements (handle, asrep,
372 "cname.name-string", &j);
373 if (res != SHISHI_OK)
374 return res;
376 if (i != j)
377 return SHISHI_CNAME_MISMATCH;
379 for (i = 1; i <= j; i++)
381 asprintf (&format, "req-body.cname.name-string.?%d", i);
382 res = shishi_asn1_read (handle, asreq, format, &reqcname, &reqcnamelen);
383 free (format);
384 if (res != SHISHI_OK)
385 return res;
387 asprintf (&format, "cname.name-string.?%d", i);
388 res = shishi_asn1_read (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 (VERBOSENOISE (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_read (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_read (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 char *salt;
648 size_t saltlen;
649 int res;
650 Shishi_key *key;
651 int keytype;
653 res = shishi_as_derive_salt (handle, asreq, asrep, &salt, &saltlen);
654 if (res != SHISHI_OK)
655 return res;
657 res = shishi_kdcrep_get_enc_part_etype (handle, asrep, &keytype);
658 if (res != SHISHI_OK)
659 return res;
661 res = shishi_key_from_string (handle, keytype,
662 string, strlen (string),
663 salt, saltlen, NULL, &key);
664 if (res != SHISHI_OK)
665 return res;
667 if (VERBOSENOISE (handle))
668 shishi_key_print (handle, stderr, key);
670 res = shishi_kdc_process (handle, asreq, asrep, key,
671 SHISHI_KEYUSAGE_ENCASREPPART, enckdcreppart);
673 return res;
677 * shishi_kdc_process:
678 * @handle: shishi handle as allocated by shishi_init().
679 * @kdcreq: input variable that holds the sent KDC-REQ.
680 * @kdcrep: input variable that holds the received KDC-REP.
681 * @key: input array with key to decrypt encrypted part of KDC-REP with.
682 * @keyusage: kereros key usage value.
683 * @enckdcreppart: output variable that holds new EncKDCRepPart.
685 * Process a KDC client exchange and output decrypted EncKDCRepPart
686 * which holds details for the new ticket received. Use
687 * shishi_kdcrep_get_ticket() to extract the ticket. This function
688 * verifies the various conditions that must hold if the response is
689 * to be considered valid, specifically it compares nonces
690 * (shishi_check_nonces()) and if the exchange was a AS exchange, it
691 * also compares cname and crealm (shishi_check_cname() and
692 * shishi_check_crealm()).
694 * Usually the shishi_as_process() and shishi_tgs_process() functions
695 * should be used instead, since they simplify the decryption key
696 * computation.
698 * Return value: Returns SHISHI_OK iff the KDC client exchange was
699 * successful.
702 shishi_kdc_process (Shishi * handle,
703 Shishi_asn1 kdcreq,
704 Shishi_asn1 kdcrep,
705 Shishi_key * key, int keyusage,
706 Shishi_asn1 * enckdcreppart)
708 int res;
709 int msgtype;
712 If the reply message type is KRB_AS_REP, then the client verifies
713 that the cname and crealm fields in the cleartext portion of the
714 reply match what it requested. If any padata fields are present,
715 they may be used to derive the proper secret key to decrypt the
716 message. The client decrypts the encrypted part of the response
717 using its secret key, verifies that the nonce in the encrypted
718 part matches the nonce it supplied in its request (to detect
719 replays). It also verifies that the sname and srealm in the
720 response match those in the request (or are otherwise expected
721 values), and that the host address field is also correct. It then
722 stores the ticket, session key, start and expiration times, and
723 other information for later use. The key-expiration field from the
724 encrypted part of the response may be checked to notify the user
725 of impending key expiration (the client program could then suggest
726 remedial action, such as a password change).
729 msgtype = 0;
730 res = shishi_asn1_read_integer (handle, kdcrep, "msg-type", &msgtype);
731 if (res != SHISHI_OK)
732 return res;
734 if (msgtype == SHISHI_MSGTYPE_AS_REP)
736 res = shishi_as_check_crealm (handle, kdcreq, kdcrep);
737 if (res != SHISHI_OK)
738 return res;
740 res = shishi_as_check_cname (handle, kdcreq, kdcrep);
741 if (res != SHISHI_OK)
742 return res;
745 res = shishi_kdcrep_decrypt (handle, kdcrep, key, keyusage, enckdcreppart);
746 if (res != SHISHI_OK)
747 return res;
749 res = shishi_kdc_check_nonce (handle, kdcreq, *enckdcreppart);
750 if (res != SHISHI_OK)
751 return res;
753 return SHISHI_OK;