1 /* kdc.c --- Key distribution (AS/TGS) functions.
2 * Copyright (C) 2002-2013 Simon Josefsson
3 *
4 * This file is part of Shishi.
5 *
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.
10 *
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.
15 *
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
20 *
21 */
22
23 #include "internal.h"
24
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.
32 *
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.
38 *
39 * Return value: Returns SHISHI_OK iff successful.
40 **/
41 int
shishi_as_derive_salt(Shishi * handle,Shishi_asn1 asreq,Shishi_asn1 asrep,char ** salt,size_t * saltlen)42 shishi_as_derive_salt (Shishi * handle,
43 Shishi_asn1 asreq,
44 Shishi_asn1 asrep, char **salt, size_t * saltlen)
45 {
46 size_t i, n;
47 char *format;
48 int res;
49
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;
55
56 for (i = 1; i <= n; i++)
57 {
58 int patype;
59
60 asprintf (&format, "padata.?%ld.padata-type", i);
61 res = shishi_asn1_read_int32 (handle, asrep, format, &patype);
62 free (format);
63 if (res != SHISHI_OK)
64 return res;
65
66 if (patype == SHISHI_PA_PW_SALT)
67 {
68 asprintf (&format, "padata.?%ld.padata-value", i);
69 res = shishi_asn1_read (handle, asrep, format, salt, saltlen);
70 free (format);
71 if (res != SHISHI_OK)
72 return res;
73
74 return SHISHI_OK;
75 }
76 }
77
78 res = shishi_kdcreq_realm (handle, asreq, salt, saltlen);
79 if (res != SHISHI_OK)
80 return res;
81
82 res = shishi_asn1_number_of_elements (handle, asreq,
83 "req-body.cname.name-string", &n);
84 if (res != SHISHI_OK)
85 return res;
86
87 for (i = 1; i <= n; i++)
88 {
89 char *tmp;
90 size_t tmplen;
91
92 asprintf (&format, "req-body.cname.name-string.?%ld", i);
93 res = shishi_asn1_read (handle, asreq, format, &tmp, &tmplen);
94 free (format);
95 if (res != SHISHI_OK)
96 return res;
97
98 *saltlen += tmplen;
99
100 *salt = xrealloc (*salt, *saltlen + 1);
101 memcpy (*salt + *saltlen - tmplen, tmp, tmplen);
102 (*salt)[*saltlen] = '\0';
103 free (tmp);
104 }
105
106 return SHISHI_OK;
107 }
108
109 int
shishi_kdcreq_sendrecv_hint(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 * kdcrep,Shishi_tkts_hint * hint)110 shishi_kdcreq_sendrecv_hint (Shishi * handle,
111 Shishi_asn1 kdcreq,
112 Shishi_asn1 * kdcrep, Shishi_tkts_hint * hint)
113 {
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;
121
122 res = shishi_asn1_to_der (handle, kdcreq, &der, &der_len);
123 if (res != SHISHI_OK)
124 {
125 shishi_error_printf (handle, "Could not DER encode AS-REQ: %s\n",
126 shishi_strerror (res));
127 return res;
128 }
129
130 res = shishi_asn1_read (handle, kdcreq, "req-body.realm",
131 &realm, &realmlen);
132 if (res != SHISHI_OK)
133 {
134 shishi_error_printf (handle, "Could not get realm: %s\n",
135 shishi_error (handle));
136 return res;
137 }
138 realm = xrealloc (realm, realmlen + 1);
139 realm[realmlen] = '\0';
140
141 res = shishi_kdc_sendrecv_hint (handle, realm, der, der_len,
142 &buffer, &buflen, hint);
143 if (res != SHISHI_OK)
144 {
145 shishi_error_printf (handle, "Could not send to KDC: %s\n",
146 shishi_error (handle));
147 return res;
148 }
149 free (realm);
150 free (der);
151
152 if (VERBOSEASN1 (handle))
153 printf ("received %ld bytes\n", buflen);
154
155 *kdcrep = shishi_der2asn1_asrep (handle, buffer, buflen);
156 if (*kdcrep == NULL)
157 {
158 *kdcrep = shishi_der2asn1_tgsrep (handle, buffer, buflen);
159 if (*kdcrep == NULL)
160 {
161 *kdcrep = shishi_der2asn1_kdcrep (handle, buffer, buflen);
162 if (*kdcrep == NULL)
163 {
164 *kdcrep = shishi_der2asn1_krberror (handle, buffer, buflen);
165 if (*kdcrep == NULL)
166 {
167 shishi_error_printf
168 (handle, "Could not DER decode AS-REP/KRB-ERROR: %s",
169 shishi_error (handle));
170 return SHISHI_ASN1_ERROR;
171 }
172
173 shishi_error_clear (handle);
174 return SHISHI_GOT_KRBERROR;
175 }
176 else
177 {
178 printf
179 ("Buggy server replied with KDC-REP instead of AS-REP\n");
180 }
181 }
182 }
183 free (buffer);
184
185 return SHISHI_OK;
186 }
187
188 int
shishi_kdcreq_sendrecv(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 * kdcrep)189 shishi_kdcreq_sendrecv (Shishi * handle, Shishi_asn1 kdcreq,
190 Shishi_asn1 * kdcrep)
191 {
192 return shishi_kdcreq_sendrecv_hint (handle, kdcreq, kdcrep, NULL);
193 }
194
195 /**
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.
200 *
201 * Set crealm in KDC-REP to value in EncTicketPart.
202 *
203 * Return value: Returns SHISHI_OK if successful.
204 **/
205 int
shishi_kdc_copy_crealm(Shishi * handle,Shishi_asn1 kdcrep,Shishi_asn1 encticketpart)206 shishi_kdc_copy_crealm (Shishi * handle,
207 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
208 {
209 char *buf;
210 size_t buflen;
211 int res;
212
213 res = shishi_asn1_read (handle, encticketpart, "crealm", &buf, &buflen);
214 if (res != SHISHI_OK)
215 return res;
216
217 res = shishi_asn1_write (handle, kdcrep, "crealm", buf, buflen);
218 free (buf);
219 if (res != SHISHI_OK)
220 return res;
221
222 return SHISHI_OK;
223 }
224
225 /**
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.
230 *
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().
234 *
235 * Return value: Returns SHISHI_OK if successful,
236 * SHISHI_REALM_MISMATCH if the values differ, or an error code.
237 **/
238 int
shishi_as_check_crealm(Shishi * handle,Shishi_asn1 asreq,Shishi_asn1 asrep)239 shishi_as_check_crealm (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
240 {
241 char *reqrealm, *reprealm;
242 size_t reqrealmlen, reprealmlen;
243 int res;
244
245 res = shishi_asn1_read (handle, asreq, "req-body.realm",
246 &reqrealm, &reqrealmlen);
247 if (res != SHISHI_OK)
248 {
249 shishi_error_printf (handle, "Could not read request realm: %s\n",
250 shishi_strerror (res));
251 return res;
252 }
253
254 res = shishi_asn1_read (handle, asrep, "crealm", &reprealm, &reprealmlen);
255 if (res != SHISHI_OK)
256 {
257 shishi_error_printf (handle, "Could not read reply realm: %s\n",
258 shishi_strerror (res));
259 return res;
260 }
261
262 reqrealm[reqrealmlen] = '\0';
263 reprealm[reprealmlen] = '\0';
264
265 if (VERBOSEASN1 (handle))
266 {
267 printf ("request realm: %s\n", reqrealm);
268 printf ("reply realm: %s\n", reprealm);
269 }
270
271 res = strcmp (reqrealm, reprealm) != 0;
272
273 free (reqrealm);
274 free (reprealm);
275
276 if (res)
277 return SHISHI_REALM_MISMATCH;
278
279 return SHISHI_OK;
280 }
281
282 /**
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.
287 *
288 * Set cname in KDC-REP to value in EncTicketPart.
289 *
290 * Return value: Returns SHISHI_OK if successful.
291 **/
292 int
shishi_kdc_copy_cname(Shishi * handle,Shishi_asn1 kdcrep,Shishi_asn1 encticketpart)293 shishi_kdc_copy_cname (Shishi * handle,
294 Shishi_asn1 kdcrep, Shishi_asn1 encticketpart)
295 {
296 char *buf;
297 char *format;
298 size_t buflen, i, n;
299 int res;
300
301 res = shishi_asn1_read (handle, encticketpart,
302 "cname.name-type", &buf, &buflen);
303 if (res != SHISHI_OK)
304 return res;
305
306 res = shishi_asn1_write (handle, kdcrep, "cname.name-type", buf, buflen);
307 free (buf);
308 if (res != SHISHI_OK)
309 return res;
310
311 res = shishi_asn1_number_of_elements (handle, encticketpart,
312 "cname.name-string", &n);
313 if (res != SHISHI_OK)
314 return res;
315
316 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", NULL, 0);
317 if (res != SHISHI_OK)
318 return res;
319
320 for (i = 1; i <= n; i++)
321 {
322 res = shishi_asn1_write (handle, kdcrep, "cname.name-string", "NEW", 1);
323 if (res != SHISHI_OK)
324 return res;
325
326 asprintf (&format, "cname.name-string.?%ld", i);
327 res = shishi_asn1_read (handle, encticketpart, format, &buf, &buflen);
328 free (format);
329 if (res != SHISHI_OK)
330 return res;
331
332 asprintf (&format, "cname.name-string.?%ld", 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;
338 }
339
340 return SHISHI_OK;
341 }
342
343 /**
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.
348 *
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().
352 *
353 * Return value: Returns SHISHI_OK if successful,
354 * SHISHI_CNAME_MISMATCH if the values differ, or an error code.
355 **/
356 int
shishi_as_check_cname(Shishi * handle,Shishi_asn1 asreq,Shishi_asn1 asrep)357 shishi_as_check_cname (Shishi * handle, Shishi_asn1 asreq, Shishi_asn1 asrep)
358 {
359 char *reqcname, *repcname;
360 size_t reqcnamelen, repcnamelen, i, j;
361 char *format;
362 int res;
363
364 /* We do not compare msg-type as recommended on the ietf-krb-wg list */
365
366 res = shishi_asn1_number_of_elements (handle, asreq,
367 "req-body.cname.name-string", &i);
368 if (res != SHISHI_OK)
369 return res;
370
371 res = shishi_asn1_number_of_elements (handle, asrep,
372 "cname.name-string", &j);
373 if (res != SHISHI_OK)
374 return res;
375
376 if (i != j)
377 return SHISHI_CNAME_MISMATCH;
378
379 for (i = 1; i <= j; i++)
380 {
381 asprintf (&format, "req-body.cname.name-string.?%ld", i);
382 res = shishi_asn1_read (handle, asreq, format, &reqcname, &reqcnamelen);
383 free (format);
384 if (res != SHISHI_OK)
385 return res;
386
387 asprintf (&format, "cname.name-string.?%ld", i);
388 res = shishi_asn1_read (handle, asrep, format, &repcname, &repcnamelen);
389 free (format);
390 if (res != SHISHI_OK)
391 return res;
392
393 if (VERBOSEASN1 (handle))
394 {
395 reqcname[reqcnamelen] = '\0';
396 repcname[repcnamelen] = '\0';
397 printf ("request cname %ld: %s\n", i, reqcname);
398 printf ("reply cname %ld: %s\n", i, repcname);
399 }
400
401 res = (reqcnamelen != repcnamelen) ||
402 (memcmp (reqcname, repcname, reqcnamelen) != 0);
403
404 free (reqcname);
405 free (repcname);
406
407 if (res)
408 return SHISHI_CNAME_MISMATCH;
409 }
410
411 return SHISHI_OK;
412 }
413
414 /**
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.
419 *
420 * Set nonce in EncKDCRepPart to value in KDC-REQ.
421 *
422 * Return value: Returns SHISHI_OK if successful.
423 **/
424 int
shishi_kdc_copy_nonce(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 enckdcreppart)425 shishi_kdc_copy_nonce (Shishi * handle,
426 Shishi_asn1 kdcreq, Shishi_asn1 enckdcreppart)
427 {
428 int res;
429 uint32_t nonce;
430
431 res = shishi_kdcreq_nonce (handle, kdcreq, &nonce);
432 if (res != SHISHI_OK)
433 return res;
434
435 res = shishi_enckdcreppart_nonce_set (handle, enckdcreppart, nonce);
436 if (res != SHISHI_OK)
437 return res;
438
439 return SHISHI_OK;
440 }
441
442 static int
shishi_kdc_check_nonce_1(Shishi * handle,char * reqnonce,size_t reqnoncelen,char * repnonce,size_t repnoncelen)443 shishi_kdc_check_nonce_1 (Shishi * handle,
444 char *reqnonce, size_t reqnoncelen,
445 char *repnonce, size_t repnoncelen)
446 {
447 if (VERBOSENOISE (handle))
448 {
449 size_t i;
450
451 printf ("request nonce (len=%ld) ", reqnoncelen);
452 for (i = 0; i < reqnoncelen; i++)
453 printf ("%02x", reqnonce[i] & 0xFF);
454 printf ("\n");
455 printf ("reply nonce (len=%ld) ", repnoncelen);
456 for (i = 0; i < repnoncelen; i++)
457 printf ("%02x", repnonce[i] & 0xFF);
458 printf ("\n");
459 }
460
461 if (reqnoncelen > 4 && repnoncelen == 4)
462 {
463 /* This case warrants some explanation.
464 *
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.
473 *
474 */
475
476 if (memcmp (reqnonce + reqnoncelen - 4, repnonce, 4) != 0)
477 return SHISHI_NONCE_MISMATCH;
478
479 shishi_warn (handle, "server truncated long nonce to 4 bytes");
480
481 return SHISHI_OK;
482 }
483
484 if (reqnoncelen != repnoncelen ||
485 memcmp (reqnonce, repnonce, repnoncelen) != 0)
486 return SHISHI_NONCE_MISMATCH;
487
488 return SHISHI_OK;
489 }
490
491 /**
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.
496 *
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.
500 *
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.
505 **/
506 int
shishi_kdc_check_nonce(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 enckdcreppart)507 shishi_kdc_check_nonce (Shishi * handle,
508 Shishi_asn1 kdcreq, Shishi_asn1 enckdcreppart)
509 {
510 char *reqnonce;
511 char *repnonce;
512 size_t reqnoncelen, repnoncelen;
513 int res;
514
515 res = shishi_asn1_read (handle, kdcreq, "req-body.nonce",
516 &reqnonce, &reqnoncelen);
517 if (res != SHISHI_OK)
518 {
519 shishi_error_printf (handle, "Could not read request nonce: %s\n",
520 shishi_strerror (res));
521 return res;
522 }
523
524 res = shishi_asn1_read (handle, enckdcreppart, "nonce",
525 &repnonce, &repnoncelen);
526 if (res != SHISHI_OK)
527 {
528 free (reqnonce);
529 shishi_error_printf (handle, "Could not read reply nonce: %s\n",
530 shishi_strerror (res));
531 return res;
532 }
533
534 res = shishi_kdc_check_nonce_1 (handle, reqnonce, reqnoncelen,
535 repnonce, repnoncelen);
536
537 free (reqnonce);
538 free (repnonce);
539
540 return res;
541 }
542
543 /**
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.
551 *
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.
556 *
557 * Return value: Returns SHISHI_OK iff the TGS client exchange was
558 * successful.
559 **/
560 int
shishi_tgs_process(Shishi * handle,Shishi_asn1 tgsreq,Shishi_asn1 tgsrep,Shishi_asn1 authenticator,Shishi_asn1 oldenckdcreppart,Shishi_asn1 * enckdcreppart)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)
566 {
567 Shishi_key *tktkey;
568 Shishi_key *subkey;
569 int use_subkey;
570 int etype;
571 int res;
572
573 res = shishi_kdcrep_get_enc_part_etype (handle, tgsrep, &etype);
574 if (res != SHISHI_OK)
575 return res;
576
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;
581
582 res = shishi_enckdcreppart_get_key (handle, oldenckdcreppart, &tktkey);
583 if (res != SHISHI_OK)
584 return res;
585
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);
595
596 /* Entire if statement to work around buggy KDCs. */
597 if (use_subkey && (res == SHISHI_CRYPTO_ERROR ||
598 res == SHISHI_TGSREP_BAD_KEYTYPE))
599 {
600 int tmpres;
601
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);
609
610 /* if bug workaround code didn't help, return original error. */
611 if (tmpres != SHISHI_OK)
612 return res;
613
614 shishi_warn (handle, "KDC bug: Reply encrypted using wrong key.");
615
616 res = tmpres;
617 }
618
619 if (res != SHISHI_OK)
620 return res;
621
622 return SHISHI_OK;
623 }
624
625 /**
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.
632 *
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.
637 *
638 * Return value: Returns SHISHI_OK iff the AS client exchange was
639 * successful.
640 **/
641 int
shishi_as_process(Shishi * handle,Shishi_asn1 asreq,Shishi_asn1 asrep,const char * string,Shishi_asn1 * enckdcreppart)642 shishi_as_process (Shishi * handle,
643 Shishi_asn1 asreq,
644 Shishi_asn1 asrep,
645 const char *string, Shishi_asn1 * enckdcreppart)
646 {
647 char *salt;
648 size_t saltlen;
649 int res;
650 Shishi_key *key;
651 int keytype;
652
653 res = shishi_as_derive_salt (handle, asreq, asrep, &salt, &saltlen);
654 if (res != SHISHI_OK)
655 return res;
656
657 res = shishi_kdcrep_get_enc_part_etype (handle, asrep, &keytype);
658 if (res != SHISHI_OK)
659 return res;
660
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;
666
667 if (VERBOSENOISE (handle))
668 shishi_key_print (handle, stderr, key);
669
670 res = shishi_kdc_process (handle, asreq, asrep, key,
671 SHISHI_KEYUSAGE_ENCASREPPART, enckdcreppart);
672
673 return res;
674 }
675
676 /**
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.
684 *
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_kdc_check_nonce()) and if the exchange was a AS exchange,
691 * it also compares cname and crealm (shishi_as_check_cname() and
692 * shishi_as_check_crealm()).
693 *
694 * Usually the shishi_as_process() and shishi_tgs_process() functions
695 * should be used instead, since they simplify the decryption key
696 * computation.
697 *
698 * Return value: Returns SHISHI_OK iff the KDC client exchange was
699 * successful.
700 **/
701 int
shishi_kdc_process(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 kdcrep,Shishi_key * key,int keyusage,Shishi_asn1 * enckdcreppart)702 shishi_kdc_process (Shishi * handle,
703 Shishi_asn1 kdcreq,
704 Shishi_asn1 kdcrep,
705 Shishi_key * key, int keyusage,
706 Shishi_asn1 * enckdcreppart)
707 {
708 int res;
709 int msgtype;
710
711 /*
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).
727 */
728
729 msgtype = 0;
730 res = shishi_asn1_read_integer (handle, kdcrep, "msg-type", &msgtype);
731 if (res != SHISHI_OK)
732 return res;
733
734 if (msgtype == SHISHI_MSGTYPE_AS_REP)
735 {
736 res = shishi_as_check_crealm (handle, kdcreq, kdcrep);
737 if (res != SHISHI_OK)
738 return res;
739
740 res = shishi_as_check_cname (handle, kdcreq, kdcrep);
741 if (res != SHISHI_OK)
742 return res;
743 }
744
745 res = shishi_kdcrep_decrypt (handle, kdcrep, key, keyusage, enckdcreppart);
746 if (res != SHISHI_OK)
747 return res;
748
749 res = shishi_kdc_check_nonce (handle, kdcreq, *enckdcreppart);
750 if (res != SHISHI_OK)
751 return res;
752
753 return SHISHI_OK;
754 }
755