Branch data Line data Source code
1 : : /* kdc.c --- Key distribution (AS/TGS) functions.
2 : : * Copyright (C) 2002, 2003, 2004, 2007, 2010 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
42 : 0 : 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 : 0 : res = shishi_asn1_number_of_elements (handle, asrep, "padata", &n);
51 [ # # ]: 0 : if (res == SHISHI_ASN1_NO_ELEMENT)
52 : 0 : n = 0;
53 [ # # ]: 0 : else if (res != SHISHI_OK)
54 : 0 : return res;
55 : :
56 [ # # ]: 0 : for (i = 1; i <= n; i++)
57 : : {
58 : : int patype;
59 : :
60 : 0 : asprintf (&format, "padata.?%d.padata-type", i);
61 : 0 : res = shishi_asn1_read_int32 (handle, asrep, format, &patype);
62 : 0 : free (format);
63 [ # # ]: 0 : if (res != SHISHI_OK)
64 : 0 : return res;
65 : :
66 [ # # ]: 0 : if (patype == SHISHI_PA_PW_SALT)
67 : : {
68 : 0 : asprintf (&format, "padata.?%d.padata-value", i);
69 : 0 : res = shishi_asn1_read (handle, asrep, format, salt, saltlen);
70 : 0 : free (format);
71 [ # # ]: 0 : if (res != SHISHI_OK)
72 : 0 : return res;
73 : :
74 : 0 : return SHISHI_OK;
75 : : }
76 : : }
77 : :
78 : 0 : res = shishi_kdcreq_realm (handle, asreq, salt, saltlen);
79 [ # # ]: 0 : if (res != SHISHI_OK)
80 : 0 : return res;
81 : :
82 : 0 : res = shishi_asn1_number_of_elements (handle, asreq,
83 : : "req-body.cname.name-string", &n);
84 [ # # ]: 0 : if (res != SHISHI_OK)
85 : 0 : return res;
86 : :
87 [ # # ]: 0 : for (i = 1; i <= n; i++)
88 : : {
89 : : char *tmp;
90 : : size_t tmplen;
91 : :
92 : 0 : asprintf (&format, "req-body.cname.name-string.?%d", i);
93 : 0 : res = shishi_asn1_read (handle, asreq, format, &tmp, &tmplen);
94 : 0 : free (format);
95 [ # # ]: 0 : if (res != SHISHI_OK)
96 : 0 : return res;
97 : :
98 : 0 : *saltlen += tmplen;
99 : :
100 : 0 : *salt = xrealloc (*salt, *saltlen + 1);
101 : 0 : memcpy (*salt + *saltlen - tmplen, tmp, tmplen);
102 : 0 : (*salt)[*saltlen] = '\0';
103 : 0 : free (tmp);
104 : : }
105 : :
106 : 0 : return SHISHI_OK;
107 : : }
108 : :
109 : : int
110 : 0 : 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 : 0 : res = shishi_asn1_to_der (handle, kdcreq, &der, &der_len);
123 [ # # ]: 0 : if (res != SHISHI_OK)
124 : : {
125 : 0 : shishi_error_printf (handle, "Could not DER encode AS-REQ: %s\n",
126 : : shishi_strerror (res));
127 : 0 : return res;
128 : : }
129 : :
130 : 0 : res = shishi_asn1_read (handle, kdcreq, "req-body.realm",
131 : : &realm, &realmlen);
132 [ # # ]: 0 : if (res != SHISHI_OK)
133 : : {
134 : 0 : shishi_error_printf (handle, "Could not get realm: %s\n",
135 : : shishi_error (handle));
136 : 0 : return res;
137 : : }
138 : 0 : realm = xrealloc (realm, realmlen + 1);
139 : 0 : realm[realmlen] = '\0';
140 : :
141 : 0 : res = shishi_kdc_sendrecv_hint (handle, realm, der, der_len,
142 : : &buffer, &buflen, hint);
143 [ # # ]: 0 : if (res != SHISHI_OK)
144 : : {
145 : 0 : shishi_error_printf (handle, "Could not send to KDC: %s\n",
146 : : shishi_error (handle));
147 : 0 : return res;
148 : : }
149 : 0 : free (realm);
150 : 0 : free (der);
151 : :
152 [ # # ]: 0 : if (VERBOSEASN1 (handle))
153 : 0 : printf ("received %d bytes\n", buflen);
154 : :
155 : 0 : *kdcrep = shishi_der2asn1_asrep (handle, buffer, buflen);
156 [ # # ]: 0 : if (*kdcrep == NULL)
157 : : {
158 : 0 : *kdcrep = shishi_der2asn1_tgsrep (handle, buffer, buflen);
159 [ # # ]: 0 : if (*kdcrep == NULL)
160 : : {
161 : 0 : *kdcrep = shishi_der2asn1_kdcrep (handle, buffer, buflen);
162 [ # # ]: 0 : if (*kdcrep == NULL)
163 : : {
164 : 0 : *kdcrep = shishi_der2asn1_krberror (handle, buffer, buflen);
165 [ # # ]: 0 : if (*kdcrep == NULL)
166 : : {
167 : 0 : shishi_error_printf
168 : : (handle, "Could not DER decode AS-REP/KRB-ERROR: %s",
169 : : shishi_error (handle));
170 : 0 : return SHISHI_ASN1_ERROR;
171 : : }
172 : :
173 : 0 : shishi_error_clear (handle);
174 : 0 : return SHISHI_GOT_KRBERROR;
175 : : }
176 : : else
177 : : {
178 : 0 : printf
179 : : ("Buggy server replied with KDC-REP instead of AS-REP\n");
180 : : }
181 : : }
182 : : }
183 : 0 : free (buffer);
184 : :
185 : 0 : return SHISHI_OK;
186 : : }
187 : :
188 : : int
189 : 0 : shishi_kdcreq_sendrecv (Shishi * handle, Shishi_asn1 kdcreq,
190 : : Shishi_asn1 * kdcrep)
191 : : {
192 : 0 : 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
206 : 0 : 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 : 0 : res = shishi_asn1_read (handle, encticketpart, "crealm", &buf, &buflen);
214 [ # # ]: 0 : if (res != SHISHI_OK)
215 : 0 : return res;
216 : :
217 : 0 : res = shishi_asn1_write (handle, kdcrep, "crealm", buf, buflen);
218 : 0 : free (buf);
219 [ # # ]: 0 : if (res != SHISHI_OK)
220 : 0 : return res;
221 : :
222 : 0 : 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
239 : 0 : 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 : 0 : res = shishi_asn1_read (handle, asreq, "req-body.realm",
246 : : &reqrealm, &reqrealmlen);
247 [ # # ]: 0 : if (res != SHISHI_OK)
248 : : {
249 : 0 : shishi_error_printf (handle, "Could not read request realm: %s\n",
250 : : shishi_strerror (res));
251 : 0 : return res;
252 : : }
253 : :
254 : 0 : res = shishi_asn1_read (handle, asrep, "crealm", &reprealm, &reprealmlen);
255 [ # # ]: 0 : if (res != SHISHI_OK)
256 : : {
257 : 0 : shishi_error_printf (handle, "Could not read reply realm: %s\n",
258 : : shishi_strerror (res));
259 : 0 : return res;
260 : : }
261 : :
262 : 0 : reqrealm[reqrealmlen] = '\0';
263 : 0 : reprealm[reprealmlen] = '\0';
264 : :
265 [ # # ]: 0 : if (VERBOSEASN1 (handle))
266 : : {
267 : 0 : printf ("request realm: %s\n", reqrealm);
268 : 0 : printf ("reply realm: %s\n", reprealm);
269 : : }
270 : :
271 : 0 : res = strcmp (reqrealm, reprealm) != 0;
272 : :
273 : 0 : free (reqrealm);
274 : 0 : free (reprealm);
275 : :
276 [ # # ]: 0 : if (res)
277 : 0 : return SHISHI_REALM_MISMATCH;
278 : :
279 : 0 : 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
293 : 0 : 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 : 0 : res = shishi_asn1_read (handle, encticketpart,
302 : : "cname.name-type", &buf, &buflen);
303 [ # # ]: 0 : if (res != SHISHI_OK)
304 : 0 : return res;
305 : :
306 : 0 : res = shishi_asn1_write (handle, kdcrep, "cname.name-type", buf, buflen);
307 : 0 : free (buf);
308 [ # # ]: 0 : if (res != SHISHI_OK)
309 : 0 : return res;
310 : :
311 : 0 : res = shishi_asn1_number_of_elements (handle, encticketpart,
312 : : "cname.name-string", &n);
313 [ # # ]: 0 : if (res != SHISHI_OK)
314 : 0 : return res;
315 : :
316 : 0 : res = shishi_asn1_write (handle, kdcrep, "cname.name-string", NULL, 0);
317 [ # # ]: 0 : if (res != SHISHI_OK)
318 : 0 : return res;
319 : :
320 [ # # ]: 0 : for (i = 1; i <= n; i++)
321 : : {
322 : 0 : res = shishi_asn1_write (handle, kdcrep, "cname.name-string", "NEW", 1);
323 [ # # ]: 0 : if (res != SHISHI_OK)
324 : 0 : return res;
325 : :
326 : 0 : asprintf (&format, "cname.name-string.?%d", i);
327 : 0 : res = shishi_asn1_read (handle, encticketpart, format, &buf, &buflen);
328 : 0 : free (format);
329 [ # # ]: 0 : if (res != SHISHI_OK)
330 : 0 : return res;
331 : :
332 : 0 : asprintf (&format, "cname.name-string.?%d", i);
333 : 0 : res = shishi_asn1_write (handle, kdcrep, format, buf, buflen);
334 : 0 : free (format);
335 : 0 : free (buf);
336 [ # # ]: 0 : if (res != SHISHI_OK)
337 : 0 : return res;
338 : : }
339 : :
340 : 0 : 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
357 : 0 : 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 : 0 : res = shishi_asn1_number_of_elements (handle, asreq,
367 : : "req-body.cname.name-string", &i);
368 [ # # ]: 0 : if (res != SHISHI_OK)
369 : 0 : return res;
370 : :
371 : 0 : res = shishi_asn1_number_of_elements (handle, asrep,
372 : : "cname.name-string", &j);
373 [ # # ]: 0 : if (res != SHISHI_OK)
374 : 0 : return res;
375 : :
376 [ # # ]: 0 : if (i != j)
377 : 0 : return SHISHI_CNAME_MISMATCH;
378 : :
379 [ # # ]: 0 : for (i = 1; i <= j; i++)
380 : : {
381 : 0 : asprintf (&format, "req-body.cname.name-string.?%d", i);
382 : 0 : res = shishi_asn1_read (handle, asreq, format, &reqcname, &reqcnamelen);
383 : 0 : free (format);
384 [ # # ]: 0 : if (res != SHISHI_OK)
385 : 0 : return res;
386 : :
387 : 0 : asprintf (&format, "cname.name-string.?%d", i);
388 : 0 : res = shishi_asn1_read (handle, asrep, format, &repcname, &repcnamelen);
389 : 0 : free (format);
390 [ # # ]: 0 : if (res != SHISHI_OK)
391 : 0 : return res;
392 : :
393 [ # # ]: 0 : if (VERBOSEASN1 (handle))
394 : : {
395 : 0 : reqcname[reqcnamelen] = '\0';
396 : 0 : repcname[repcnamelen] = '\0';
397 : 0 : printf ("request cname %d: %s\n", i, reqcname);
398 : 0 : printf ("reply cname %d: %s\n", i, repcname);
399 : : }
400 : :
401 [ # # ][ # # ]: 0 : res = (reqcnamelen != repcnamelen) ||
402 : 0 : (memcmp (reqcname, repcname, reqcnamelen) != 0);
403 : :
404 : 0 : free (reqcname);
405 : 0 : free (repcname);
406 : :
407 [ # # ]: 0 : if (res)
408 : 0 : return SHISHI_CNAME_MISMATCH;
409 : : }
410 : :
411 : 0 : 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
425 : 1 : shishi_kdc_copy_nonce (Shishi * handle,
426 : : Shishi_asn1 kdcreq, Shishi_asn1 enckdcreppart)
427 : : {
428 : : int res;
429 : : uint32_t nonce;
430 : :
431 : 1 : res = shishi_kdcreq_nonce (handle, kdcreq, &nonce);
432 [ - + ]: 1 : if (res != SHISHI_OK)
433 : 0 : return res;
434 : :
435 : 1 : res = shishi_enckdcreppart_nonce_set (handle, enckdcreppart, nonce);
436 [ - + ]: 1 : if (res != SHISHI_OK)
437 : 0 : return res;
438 : :
439 : 1 : return SHISHI_OK;
440 : : }
441 : :
442 : : static int
443 : 0 : shishi_kdc_check_nonce_1 (Shishi * handle,
444 : : char *reqnonce, size_t reqnoncelen,
445 : : char *repnonce, size_t repnoncelen)
446 : : {
447 [ # # ]: 0 : if (VERBOSENOISE (handle))
448 : : {
449 : : size_t i;
450 : :
451 : 0 : printf ("request nonce (len=%d) ", reqnoncelen);
452 [ # # ]: 0 : for (i = 0; i < reqnoncelen; i++)
453 : 0 : printf ("%02x", reqnonce[i] & 0xFF);
454 : 0 : printf ("\n");
455 : 0 : printf ("reply nonce (len=%d) ", repnoncelen);
456 [ # # ]: 0 : for (i = 0; i < repnoncelen; i++)
457 : 0 : printf ("%02x", repnonce[i] & 0xFF);
458 : 0 : printf ("\n");
459 : : }
460 : :
461 [ # # ][ # # ]: 0 : 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 [ # # ]: 0 : if (memcmp (reqnonce + reqnoncelen - 4, repnonce, 4) != 0)
477 : 0 : return SHISHI_NONCE_MISMATCH;
478 : :
479 : 0 : shishi_warn (handle, "server truncated long nonce to 4 bytes");
480 : :
481 : 0 : return SHISHI_OK;
482 : : }
483 : :
484 [ # # ][ # # ]: 0 : if (reqnoncelen != repnoncelen ||
485 : 0 : memcmp (reqnonce, repnonce, repnoncelen) != 0)
486 : 0 : return SHISHI_NONCE_MISMATCH;
487 : :
488 : 0 : 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
507 : 0 : 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 : 0 : res = shishi_asn1_read (handle, kdcreq, "req-body.nonce",
516 : : &reqnonce, &reqnoncelen);
517 [ # # ]: 0 : if (res != SHISHI_OK)
518 : : {
519 : 0 : shishi_error_printf (handle, "Could not read request nonce: %s\n",
520 : : shishi_strerror (res));
521 : 0 : return res;
522 : : }
523 : :
524 : 0 : res = shishi_asn1_read (handle, enckdcreppart, "nonce",
525 : : &repnonce, &repnoncelen);
526 [ # # ]: 0 : if (res != SHISHI_OK)
527 : : {
528 : 0 : free (reqnonce);
529 : 0 : shishi_error_printf (handle, "Could not read reply nonce: %s\n",
530 : : shishi_strerror (res));
531 : 0 : return res;
532 : : }
533 : :
534 : 0 : res = shishi_kdc_check_nonce_1 (handle, reqnonce, reqnoncelen,
535 : : repnonce, repnoncelen);
536 : :
537 : 0 : free (reqnonce);
538 : 0 : free (repnonce);
539 : :
540 : 0 : 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
561 : 0 : 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 : 0 : res = shishi_kdcrep_get_enc_part_etype (handle, tgsrep, &etype);
574 [ # # ]: 0 : if (res != SHISHI_OK)
575 : 0 : return res;
576 : :
577 : 0 : res = shishi_authenticator_get_subkey (handle, authenticator, &subkey);
578 : 0 : use_subkey = (res != SHISHI_ASN1_NO_ELEMENT);
579 [ # # # # ]: 0 : if (res != SHISHI_OK && res != SHISHI_ASN1_NO_ELEMENT)
580 : 0 : return res;
581 : :
582 : 0 : res = shishi_enckdcreppart_get_key (handle, oldenckdcreppart, &tktkey);
583 [ # # ]: 0 : if (res != SHISHI_OK)
584 : 0 : return res;
585 : :
586 [ # # ][ # # ]: 0 : if (etype != shishi_key_type (use_subkey ? subkey : tktkey))
587 : 0 : res = SHISHI_TGSREP_BAD_KEYTYPE;
588 : : else
589 [ # # ][ # # ]: 0 : 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 [ # # ][ # # ]: 0 : 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 [ # # ]: 0 : if (etype != shishi_key_type (tktkey))
604 : 0 : tmpres = SHISHI_TGSREP_BAD_KEYTYPE;
605 : : else
606 : 0 : 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 [ # # ]: 0 : if (tmpres != SHISHI_OK)
612 : 0 : return res;
613 : :
614 : 0 : shishi_warn (handle, "KDC bug: Reply encrypted using wrong key.");
615 : :
616 : 0 : res = tmpres;
617 : : }
618 : :
619 [ # # ]: 0 : if (res != SHISHI_OK)
620 : 0 : return res;
621 : :
622 : 0 : 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
642 : 0 : 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 : 0 : res = shishi_as_derive_salt (handle, asreq, asrep, &salt, &saltlen);
654 [ # # ]: 0 : if (res != SHISHI_OK)
655 : 0 : return res;
656 : :
657 : 0 : res = shishi_kdcrep_get_enc_part_etype (handle, asrep, &keytype);
658 [ # # ]: 0 : if (res != SHISHI_OK)
659 : 0 : return res;
660 : :
661 : 0 : res = shishi_key_from_string (handle, keytype,
662 : : string, strlen (string),
663 : : salt, saltlen, NULL, &key);
664 [ # # ]: 0 : if (res != SHISHI_OK)
665 : 0 : return res;
666 : :
667 [ # # ]: 0 : if (VERBOSENOISE (handle))
668 : 0 : shishi_key_print (handle, stderr, key);
669 : :
670 : 0 : res = shishi_kdc_process (handle, asreq, asrep, key,
671 : : SHISHI_KEYUSAGE_ENCASREPPART, enckdcreppart);
672 : :
673 : 0 : 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
702 : 0 : 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 : 0 : msgtype = 0;
730 : 0 : res = shishi_asn1_read_integer (handle, kdcrep, "msg-type", &msgtype);
731 [ # # ]: 0 : if (res != SHISHI_OK)
732 : 0 : return res;
733 : :
734 [ # # ]: 0 : if (msgtype == SHISHI_MSGTYPE_AS_REP)
735 : : {
736 : 0 : res = shishi_as_check_crealm (handle, kdcreq, kdcrep);
737 [ # # ]: 0 : if (res != SHISHI_OK)
738 : 0 : return res;
739 : :
740 : 0 : res = shishi_as_check_cname (handle, kdcreq, kdcrep);
741 [ # # ]: 0 : if (res != SHISHI_OK)
742 : 0 : return res;
743 : : }
744 : :
745 : 0 : res = shishi_kdcrep_decrypt (handle, kdcrep, key, keyusage, enckdcreppart);
746 [ # # ]: 0 : if (res != SHISHI_OK)
747 : 0 : return res;
748 : :
749 : 0 : res = shishi_kdc_check_nonce (handle, kdcreq, *enckdcreppart);
750 [ # # ]: 0 : if (res != SHISHI_OK)
751 : 0 : return res;
752 : :
753 : 0 : return SHISHI_OK;
754 : : }
|