1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/rd_req_dec.c */
3 /*
4 * Copyright (c) 1994 CyberSAFE Corporation.
5 * Copyright 1990,1991,2007,2008 by the Massachusetts Institute of Technology.
6 * All Rights Reserved.
7 *
8 * Export of this software from the United States of America may
9 * require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
12 *
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * Neither M.I.T., the Open Computing Security Group, nor
24 * CyberSAFE Corporation make any representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
27 *
28 *
29 * krb5_rd_req_decoded()
30 */
31
32 #include "k5-int.h"
33 #include "auth_con.h"
34 #include "authdata.h"
35 #include "int-proto.h"
36 #include "os-proto.h"
37
38 /*
39 * essentially the same as krb_rd_req, but uses a decoded AP_REQ as
40 * the input rather than an encoded input.
41 */
42 /*
43 * Parses a KRB_AP_REQ message, returning its contents.
44 *
45 * server specifies the expected server's name for the ticket; if NULL, then
46 * any server will be accepted if the key can be found, and the caller should
47 * verify that the principal is something it trusts. With the exception of the
48 * kdb keytab, the ticket's server field need not match the name passed in for
49 * server. All that is required is that the ticket be encrypted with a key
50 * from the keytab associated with the specified server principal. This
51 * permits the KDC to have a set of aliases for the server without keeping
52 * this information consistent with the server. So, when server is non-null,
53 * the principal expected by the application needs to be consistent with the
54 * local keytab, but not with the informational name in the ticket.
55 *
56 * rcache specifies a replay detection cache used to store authenticators and
57 * server names
58 *
59 * keyproc specifies a procedure to generate a decryption key for the
60 * ticket. If keyproc is non-NULL, keyprocarg is passed to it, and the result
61 * used as a decryption key. If keyproc is NULL, then fetchfrom is checked;
62 * if it is non-NULL, it specifies a parameter name from which to retrieve the
63 * decryption key. If fetchfrom is NULL, then the default key store is
64 * consulted.
65 *
66 * authdat is set to point at allocated storage structures; the caller
67 * should free them when finished.
68 *
69 * returns system errors, encryption errors, replay errors
70 */
71
72 static krb5_error_code
73 decrypt_authenticator(krb5_context, const krb5_ap_req *,
74 krb5_authenticator **, int);
75 static krb5_error_code
76 decode_etype_list(krb5_context context,
77 const krb5_authenticator *authp,
78 krb5_enctype **desired_etypes,
79 int *desired_etypes_len);
80 static krb5_error_code
81 negotiate_etype(krb5_context context,
82 const krb5_enctype *desired_etypes,
83 int desired_etypes_len,
84 int mandatory_etypes_index,
85 const krb5_enctype *permitted_etypes,
86 int permitted_etypes_len,
87 krb5_enctype *negotiated_etype);
88
89 /* Unparse the specified server principal (which may be NULL) and the ticket
90 * server principal. */
91 static krb5_error_code
unparse_princs(krb5_context context,krb5_const_principal server,krb5_const_principal tkt_server,char ** sname_out,char ** tsname_out)92 unparse_princs(krb5_context context, krb5_const_principal server,
93 krb5_const_principal tkt_server, char **sname_out,
94 char **tsname_out)
95 {
96 krb5_error_code ret;
97 char *sname = NULL, *tsname;
98
99 *sname_out = *tsname_out = NULL;
100 if (server != NULL) {
101 ret = krb5_unparse_name(context, server, &sname);
102 if (ret)
103 return ret;
104 }
105 ret = krb5_unparse_name(context, tkt_server, &tsname);
106 if (ret) {
107 krb5_free_unparsed_name(context, sname);
108 return ret;
109 }
110 *sname_out = sname;
111 *tsname_out = tsname;
112 return 0;
113 }
114
115 /* Return a helpful code and error when we cannot look up the keytab entry for
116 * an explicit server principal using the ticket's kvno and enctype. */
117 static krb5_error_code
keytab_fetch_error(krb5_context context,krb5_error_code code,krb5_const_principal princ,krb5_const_principal tkt_server,krb5_kvno tkt_kvno,krb5_boolean explicit_server)118 keytab_fetch_error(krb5_context context, krb5_error_code code,
119 krb5_const_principal princ,
120 krb5_const_principal tkt_server, krb5_kvno tkt_kvno,
121 krb5_boolean explicit_server)
122 {
123 krb5_error_code ret;
124 char *sname = NULL, *tsname = NULL;
125
126 if (code == ENOENT || code == EPERM || code == EACCES) {
127 k5_change_error_message_code(context, code, KRB5KRB_AP_ERR_NOKEY);
128 return KRB5KRB_AP_ERR_NOKEY;
129 }
130
131 if (code == KRB5_KT_NOTFOUND) {
132 ret = explicit_server ? KRB5KRB_AP_ERR_NOKEY : KRB5KRB_AP_ERR_NOT_US;
133 k5_change_error_message_code(context, code, ret);
134 return ret;
135 }
136
137 if (code != KRB5_KT_KVNONOTFOUND)
138 return code;
139
140 assert(princ != NULL);
141 ret = unparse_princs(context, princ, tkt_server, &sname, &tsname);
142 if (ret)
143 return ret;
144 if (krb5_principal_compare(context, princ, tkt_server)) {
145 ret = KRB5KRB_AP_ERR_BADKEYVER;
146 k5_setmsg(context, ret, _("Cannot find key for %s kvno %d in keytab"),
147 sname, (int)tkt_kvno);
148 } else {
149 ret = KRB5KRB_AP_ERR_NOT_US;
150 k5_setmsg(context, ret,
151 _("Cannot find key for %s kvno %d in keytab (request ticket "
152 "server %s)"), sname, (int)tkt_kvno, tsname);
153 }
154 krb5_free_unparsed_name(context, sname);
155 krb5_free_unparsed_name(context, tsname);
156 return ret;
157 }
158
159 /* Return a helpful code and error when ticket decryption fails using the key
160 * for an explicit server principal. */
161 static krb5_error_code
integrity_error(krb5_context context,krb5_const_principal server,krb5_const_principal tkt_server)162 integrity_error(krb5_context context, krb5_const_principal server,
163 krb5_const_principal tkt_server)
164 {
165 krb5_error_code ret;
166 char *sname = NULL, *tsname = NULL;
167
168 assert(server != NULL);
169 ret = unparse_princs(context, server, tkt_server, &sname, &tsname);
170 if (ret)
171 return ret;
172
173 ret = krb5_principal_compare(context, server, tkt_server) ?
174 KRB5KRB_AP_ERR_BAD_INTEGRITY : KRB5KRB_AP_ERR_NOT_US;
175 k5_setmsg(context, ret,
176 _("Cannot decrypt ticket for %s using keytab key for %s"),
177 tsname, sname);
178 krb5_free_unparsed_name(context, sname);
179 krb5_free_unparsed_name(context, tsname);
180 return ret;
181 }
182
183 /* Return a helpful code and error when we cannot iterate over the keytab and
184 * the specified server does not match the ticket server. */
185 static krb5_error_code
nomatch_error(krb5_context context,krb5_const_principal server,krb5_const_principal tkt_server)186 nomatch_error(krb5_context context, krb5_const_principal server,
187 krb5_const_principal tkt_server)
188 {
189 krb5_error_code ret;
190 char *sname = NULL, *tsname = NULL;
191
192 assert(server != NULL);
193 ret = unparse_princs(context, server, tkt_server, &sname, &tsname);
194 if (ret)
195 return ret;
196
197 k5_setmsg(context, KRB5KRB_AP_ERR_NOT_US,
198 _("Server principal %s does not match request ticket server %s"),
199 sname, tsname);
200 krb5_free_unparsed_name(context, sname);
201 krb5_free_unparsed_name(context, tsname);
202 return KRB5KRB_AP_ERR_NOT_US;
203 }
204
205 /* Return a helpful error code and message when we fail to find a key after
206 * iterating over the keytab. */
207 static krb5_error_code
iteration_error(krb5_context context,krb5_const_principal server,krb5_const_principal tkt_server,krb5_kvno tkt_kvno,krb5_enctype tkt_etype,krb5_boolean tkt_server_mismatch,krb5_boolean found_server_match,krb5_boolean found_tkt_server,krb5_boolean found_kvno,krb5_boolean found_higher_kvno,krb5_boolean found_enctype)208 iteration_error(krb5_context context, krb5_const_principal server,
209 krb5_const_principal tkt_server, krb5_kvno tkt_kvno,
210 krb5_enctype tkt_etype, krb5_boolean tkt_server_mismatch,
211 krb5_boolean found_server_match, krb5_boolean found_tkt_server,
212 krb5_boolean found_kvno, krb5_boolean found_higher_kvno,
213 krb5_boolean found_enctype)
214 {
215 krb5_error_code ret;
216 char *sname = NULL, *tsname = NULL, encname[128];
217
218 ret = unparse_princs(context, server, tkt_server, &sname, &tsname);
219 if (ret)
220 return ret;
221 if (krb5_enctype_to_name(tkt_etype, TRUE, encname, sizeof(encname)) != 0)
222 (void)snprintf(encname, sizeof(encname), "%d", (int)tkt_etype);
223
224 if (!found_server_match) {
225 ret = KRB5KRB_AP_ERR_NOKEY;
226 if (sname == NULL) {
227 k5_setmsg(context, ret, _("No keys in keytab"));
228 } else {
229 k5_setmsg(context, ret,
230 _("Server principal %s does not match any keys in "
231 "keytab"), sname);
232 }
233 } else if (tkt_server_mismatch) {
234 assert(sname != NULL); /* Null server princ would match anything. */
235 ret = KRB5KRB_AP_ERR_NOT_US;
236 k5_setmsg(context, ret,
237 _("Request ticket server %s found in keytab but does not "
238 "match server principal %s"), tsname, sname);
239 } else if (!found_tkt_server) {
240 ret = KRB5KRB_AP_ERR_NOT_US;
241 k5_setmsg(context, ret,
242 _("Request ticket server %s not found in keytab (ticket "
243 "kvno %d)"), tsname, (int)tkt_kvno);
244 } else if (!found_kvno) {
245 ret = KRB5KRB_AP_ERR_BADKEYVER;
246 if (found_higher_kvno) {
247 k5_setmsg(context, ret,
248 _("Request ticket server %s kvno %d not found in "
249 "keytab; ticket is likely out of date"),
250 tsname, (int)tkt_kvno);
251 } else {
252 k5_setmsg(context, ret,
253 _("Request ticket server %s kvno %d not found in "
254 "keytab; keytab is likely out of date"),
255 tsname, (int)tkt_kvno);
256 }
257 } else if (!found_enctype) {
258 /* There's no defined error for having the key version but not the
259 * enctype. */
260 ret = KRB5KRB_AP_ERR_BADKEYVER;
261 k5_setmsg(context, ret,
262 _("Request ticket server %s kvno %d found in keytab but not "
263 "with enctype %s"), tsname, (int)tkt_kvno, encname);
264 } else {
265 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
266 k5_setmsg(context, ret,
267 _("Request ticket server %s kvno %d enctype %s found in "
268 "keytab but cannot decrypt ticket"),
269 tsname, (int)tkt_kvno, encname);
270 }
271
272 krb5_free_unparsed_name(context, sname);
273 krb5_free_unparsed_name(context, tsname);
274 return ret;
275 }
276
277 /* Return true if princ might match multiple principals. */
278 static inline krb5_boolean
is_matching(krb5_context context,krb5_const_principal princ)279 is_matching(krb5_context context, krb5_const_principal princ)
280 {
281 if (princ == NULL)
282 return TRUE;
283 return (princ->type == KRB5_NT_SRV_HST && princ->length == 2
284 && (princ->realm.length == 0 || princ->data[1].length == 0 ||
285 context->ignore_acceptor_hostname));
286 }
287
288 /* Decrypt the ticket in req using the key in ent. */
289 static krb5_error_code
try_one_entry(krb5_context context,const krb5_ap_req * req,krb5_keytab_entry * ent,krb5_keyblock * keyblock_out)290 try_one_entry(krb5_context context, const krb5_ap_req *req,
291 krb5_keytab_entry *ent, krb5_keyblock *keyblock_out)
292 {
293 krb5_error_code ret;
294 krb5_principal tmp = NULL;
295
296 /* Try decrypting the ticket with this entry's key. */
297 ret = krb5_decrypt_tkt_part(context, &ent->key, req->ticket);
298 if (ret)
299 return ret;
300
301 /* Make a copy of the principal for the ticket server field. */
302 ret = krb5_copy_principal(context, ent->principal, &tmp);
303 if (ret)
304 return ret;
305
306 /* Make a copy of the decrypting key if requested by the caller. */
307 if (keyblock_out != NULL) {
308 ret = krb5_copy_keyblock_contents(context, &ent->key, keyblock_out);
309 if (ret) {
310 krb5_free_principal(context, tmp);
311 return ret;
312 }
313 }
314
315 /* Make req->ticket->server indicate the actual server principal. */
316 krb5_free_principal(context, req->ticket->server);
317 req->ticket->server = tmp;
318
319 return 0;
320 }
321
322 /* Decrypt the ticket in req using a principal looked up from keytab.
323 * explicit_server should be true if this is the only usable principal. */
324 static krb5_error_code
try_one_princ(krb5_context context,const krb5_ap_req * req,krb5_const_principal princ,krb5_keytab keytab,krb5_boolean explicit_server,krb5_keyblock * keyblock_out)325 try_one_princ(krb5_context context, const krb5_ap_req *req,
326 krb5_const_principal princ, krb5_keytab keytab,
327 krb5_boolean explicit_server, krb5_keyblock *keyblock_out)
328 {
329 krb5_error_code ret;
330 krb5_keytab_entry ent;
331 krb5_kvno tkt_kvno = req->ticket->enc_part.kvno;
332 krb5_enctype tkt_etype = req->ticket->enc_part.enctype;
333 krb5_principal tkt_server = req->ticket->server;
334
335 ret = krb5_kt_get_entry(context, keytab, princ, tkt_kvno, tkt_etype, &ent);
336 if (ret) {
337 return keytab_fetch_error(context, ret, princ, tkt_server, tkt_kvno,
338 explicit_server);
339 }
340 ret = try_one_entry(context, req, &ent, keyblock_out);
341 if (ret == 0)
342 TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key);
343 (void)krb5_free_keytab_entry_contents(context, &ent);
344 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
345 return integrity_error(context, princ, req->ticket->server);
346 return ret;
347 }
348
349 /*
350 * Decrypt the ticket in req using an entry in keytab matching server (if
351 * given). Set req->ticket->server to the principal of the keytab entry used.
352 * Store the decrypting key in *keyblock_out if it is not NULL.
353 */
354 static krb5_error_code
decrypt_try_server(krb5_context context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_keyblock * keyblock_out)355 decrypt_try_server(krb5_context context, const krb5_ap_req *req,
356 krb5_const_principal server, krb5_keytab keytab,
357 krb5_keyblock *keyblock_out)
358 {
359 krb5_error_code ret;
360 krb5_keytab_entry ent;
361 krb5_kt_cursor cursor;
362 krb5_principal tkt_server = req->ticket->server;
363 krb5_kvno tkt_kvno = req->ticket->enc_part.kvno;
364 krb5_enctype tkt_etype = req->ticket->enc_part.enctype;
365 krb5_boolean similar_enctype;
366 krb5_boolean tkt_server_mismatch = FALSE, found_server_match = FALSE;
367 krb5_boolean found_tkt_server = FALSE, found_enctype = FALSE;
368 krb5_boolean found_kvno = FALSE, found_higher_kvno = FALSE;
369
370 #ifdef LEAN_CLIENT
371 return KRB5KRB_AP_WRONG_PRINC;
372 #else
373 /* If we have an explicit server principal, try just that one. */
374 if (!is_matching(context, server)) {
375 return try_one_princ(context, req, server, keytab, TRUE,
376 keyblock_out);
377 }
378
379 if (keytab->ops->start_seq_get == NULL) {
380 /* We can't iterate over the keytab. Try the principal asserted by the
381 * client if it's allowed by the server parameter. */
382 if (!krb5_sname_match(context, server, tkt_server))
383 return nomatch_error(context, server, tkt_server);
384 return try_one_princ(context, req, tkt_server, keytab, FALSE,
385 keyblock_out);
386 }
387
388 /* Scan all keys in the keytab, in case the ticket server is an alias for
389 * one of the principals in the keytab. */
390 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
391 if (ret) {
392 k5_change_error_message_code(context, ret, KRB5KRB_AP_ERR_NOKEY);
393 return KRB5KRB_AP_ERR_NOKEY;
394 }
395 while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) {
396 /* Only try keys which match the server principal. */
397 if (!krb5_sname_match(context, server, ent.principal)) {
398 if (krb5_principal_compare(context, ent.principal, tkt_server))
399 tkt_server_mismatch = TRUE;
400 (void)krb5_free_keytab_entry_contents(context, &ent);
401 continue;
402 }
403 found_server_match = TRUE;
404
405 if (krb5_c_enctype_compare(context, ent.key.enctype, tkt_etype,
406 &similar_enctype) != 0)
407 similar_enctype = FALSE;
408
409 if (krb5_principal_compare(context, ent.principal, tkt_server)) {
410 found_tkt_server = TRUE;
411 if (ent.vno == tkt_kvno) {
412 found_kvno = TRUE;
413 if (similar_enctype)
414 found_enctype = TRUE;
415 } else if (ent.vno > tkt_kvno) {
416 found_higher_kvno = TRUE;
417 }
418 }
419
420 /* Only try keys with similar enctypes to the ticket enctype. */
421 if (similar_enctype) {
422 /* Coerce inexact matches to the request enctype. */
423 ent.key.enctype = tkt_etype;
424 if (try_one_entry(context, req, &ent, keyblock_out) == 0) {
425 TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key);
426 (void)krb5_free_keytab_entry_contents(context, &ent);
427 break;
428 }
429 }
430
431 (void)krb5_free_keytab_entry_contents(context, &ent);
432 }
433
434 (void)krb5_kt_end_seq_get(context, keytab, &cursor);
435
436 if (ret != KRB5_KT_END)
437 return ret;
438 return iteration_error(context, server, tkt_server, tkt_kvno, tkt_etype,
439 tkt_server_mismatch, found_server_match,
440 found_tkt_server, found_kvno, found_higher_kvno,
441 found_enctype);
442 #endif /* LEAN_CLIENT */
443 }
444
445 static krb5_error_code
decrypt_ticket(krb5_context context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_keyblock * keyblock_out)446 decrypt_ticket(krb5_context context, const krb5_ap_req *req,
447 krb5_const_principal server, krb5_keytab keytab,
448 krb5_keyblock *keyblock_out)
449 {
450 krb5_error_code ret, dret = 0;
451 struct canonprinc iter = { server, .no_hostrealm = TRUE };
452 krb5_const_principal canonprinc;
453
454 /* Don't try to canonicalize if we're going to ignore hostnames. */
455 if (k5_sname_wildcard_host(context, server))
456 return decrypt_try_server(context, req, server, keytab, keyblock_out);
457
458 /* Try each canonicalization candidate for server. If they all fail,
459 * return the error from the last attempt. */
460 while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
461 canonprinc != NULL) {
462 dret = decrypt_try_server(context, req, canonprinc, keytab,
463 keyblock_out);
464 /* Only continue if we found no keytab entries matching canonprinc. */
465 if (dret != KRB5KRB_AP_ERR_NOKEY)
466 break;
467 }
468 free_canonprinc(&iter);
469 return (ret != 0) ? ret : dret;
470 }
471
472 static krb5_error_code
rd_req_decoded_opt(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket,int check_valid_flag)473 rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
474 const krb5_ap_req *req, krb5_const_principal server,
475 krb5_keytab keytab, krb5_flags *ap_req_options,
476 krb5_ticket **ticket, int check_valid_flag)
477 {
478 krb5_error_code retval = 0;
479 krb5_enctype *desired_etypes = NULL;
480 int desired_etypes_len = 0;
481 int rfc4537_etypes_len = 0;
482 krb5_enctype *permitted_etypes = NULL;
483 int permitted_etypes_len = 0;
484 krb5_keyblock decrypt_key;
485
486 decrypt_key.enctype = ENCTYPE_NULL;
487 decrypt_key.contents = NULL;
488 req->ticket->enc_part2 = NULL;
489
490 /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY)
491 do we need special processing here ? */
492
493 /* decrypt the ticket */
494 if ((*auth_context)->key) { /* User to User authentication */
495 if ((retval = krb5_decrypt_tkt_part(context,
496 &(*auth_context)->key->keyblock,
497 req->ticket)))
498 goto cleanup;
499 if (check_valid_flag) {
500 decrypt_key = (*auth_context)->key->keyblock;
501 (*auth_context)->key->keyblock.contents = NULL;
502 }
503 krb5_k_free_key(context, (*auth_context)->key);
504 (*auth_context)->key = NULL;
505 if (server == NULL)
506 server = req->ticket->server;
507 } else {
508 retval = decrypt_ticket(context, req, server, keytab,
509 check_valid_flag ? &decrypt_key : NULL);
510 if (retval) {
511 TRACE_RD_REQ_DECRYPT_FAIL(context, retval);
512 goto cleanup;
513 }
514 /* decrypt_ticket placed the principal of the keytab key in
515 * req->ticket->server; always use this for later steps. */
516 server = req->ticket->server;
517 }
518 TRACE_RD_REQ_TICKET(context, req->ticket->enc_part2->client,
519 req->ticket->server, req->ticket->enc_part2->session);
520
521 /* XXX this is an evil hack. check_valid_flag is set iff the call
522 is not from inside the kdc. we can use this to determine which
523 key usage to use */
524 #ifndef LEAN_CLIENT
525 if ((retval = decrypt_authenticator(context, req,
526 &((*auth_context)->authentp),
527 check_valid_flag)))
528 goto cleanup;
529 #endif
530 if (!krb5_principal_compare(context, (*auth_context)->authentp->client,
531 req->ticket->enc_part2->client)) {
532 retval = KRB5KRB_AP_ERR_BADMATCH;
533 goto cleanup;
534 }
535
536 if ((*auth_context)->remote_addr &&
537 !krb5_address_search(context, (*auth_context)->remote_addr,
538 req->ticket->enc_part2->caddrs)) {
539 retval = KRB5KRB_AP_ERR_BADADDR;
540 goto cleanup;
541 }
542
543 /* Get an rcache if necessary. */
544 if (((*auth_context)->rcache == NULL) &&
545 ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME)) {
546 retval = k5_rc_default(context, &(*auth_context)->rcache);
547 if (retval)
548 goto cleanup;
549 }
550 /* okay, now check cross-realm policy */
551
552 #if defined(_SINGLE_HOP_ONLY)
553
554 /* Single hop cross-realm tickets only */
555
556 {
557 krb5_transited *trans = &(req->ticket->enc_part2->transited);
558
559 /* If the transited list is empty, then we have at most one hop */
560 if (trans->tr_contents.length > 0 && trans->tr_contents.data[0])
561 retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
562 }
563
564 #elif defined(_NO_CROSS_REALM)
565
566 /* No cross-realm tickets */
567
568 {
569 char * lrealm;
570 krb5_data * realm;
571 krb5_transited * trans;
572
573 realm = &req->ticket->enc_part2->client->realm;
574 trans = &(req->ticket->enc_part2->transited);
575
576 /*
577 * If the transited list is empty, then we have at most one hop
578 * So we also have to check that the client's realm is the local one
579 */
580 krb5_get_default_realm(context, &lrealm);
581 if ((trans->tr_contents.length > 0 && trans->tr_contents.data[0]) ||
582 !data_eq_string(*realm, lrealm)) {
583 retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
584 }
585 free(lrealm);
586 }
587
588 #else
589
590 /* Hierarchical Cross-Realm */
591
592 {
593 krb5_data * realm;
594 krb5_transited * trans;
595 krb5_flags flags;
596
597 realm = &req->ticket->enc_part2->client->realm;
598 trans = &(req->ticket->enc_part2->transited);
599 flags = req->ticket->enc_part2->flags;
600
601 /*
602 * If the transited list is not empty and the KDC hasn't checked it,
603 * then check that all realms transited are within the hierarchy
604 * between the client's realm and the local realm.
605 */
606 if (!(flags & TKT_FLG_TRANSIT_POLICY_CHECKED) &&
607 trans->tr_contents.length > 0 && trans->tr_contents.data[0]) {
608 retval = krb5_check_transited_list(context, &(trans->tr_contents),
609 realm, &server->realm);
610 }
611 }
612
613 #endif
614
615 if (retval) goto cleanup;
616
617 /* only check rcache if sender has provided one---some services
618 may not be able to use replay caches (such as datagram servers) */
619
620 if ((*auth_context)->rcache != NULL) {
621 retval = k5_rc_store(context, (*auth_context)->rcache,
622 &req->authenticator);
623 if (retval)
624 goto cleanup;
625 }
626
627 retval = krb5int_validate_times(context, &req->ticket->enc_part2->times);
628 if (retval != 0)
629 goto cleanup;
630
631 if ((retval = krb5_check_clockskew(context, (*auth_context)->authentp->ctime)))
632 goto cleanup;
633
634 if (check_valid_flag) {
635 if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) {
636 retval = KRB5KRB_AP_ERR_TKT_INVALID;
637 goto cleanup;
638 }
639
640 if ((retval = krb5_authdata_context_init(context,
641 &(*auth_context)->ad_context)))
642 goto cleanup;
643 if ((retval = krb5int_authdata_verify(context,
644 (*auth_context)->ad_context,
645 AD_USAGE_MASK,
646 auth_context,
647 &decrypt_key,
648 req)))
649 goto cleanup;
650 }
651
652 /* read RFC 4537 etype list from sender */
653 retval = decode_etype_list(context,
654 (*auth_context)->authentp,
655 &desired_etypes,
656 &rfc4537_etypes_len);
657 if (retval != 0)
658 goto cleanup;
659
660 if (desired_etypes == NULL)
661 desired_etypes = (krb5_enctype *)calloc(4, sizeof(krb5_enctype));
662 else
663 desired_etypes = (krb5_enctype *)realloc(desired_etypes,
664 (rfc4537_etypes_len + 4) *
665 sizeof(krb5_enctype));
666 if (desired_etypes == NULL) {
667 retval = ENOMEM;
668 goto cleanup;
669 }
670
671 desired_etypes_len = rfc4537_etypes_len;
672
673 /*
674 * RFC 4537:
675 *
676 * If the EtypeList is present and the server prefers an enctype from
677 * the client's enctype list over that of the AP-REQ authenticator
678 * subkey (if that is present) or the service ticket session key, the
679 * server MUST create a subkey using that enctype. This negotiated
680 * subkey is sent in the subkey field of AP-REP message, and it is then
681 * used as the protocol key or base key [RFC3961] for subsequent
682 * communication.
683 *
684 * If the enctype of the ticket session key is included in the enctype
685 * list sent by the client, it SHOULD be the last on the list;
686 * otherwise, this enctype MUST NOT be negotiated if it was not included
687 * in the list.
688 *
689 * The second paragraph does appear to contradict the first with respect
690 * to whether it is legal to negotiate the ticket session key type if it
691 * is absent in the EtypeList. A literal reading suggests that we can use
692 * the AP-REQ subkey enctype. Also a client has no way of distinguishing
693 * a server that does not RFC 4537 from one that has chosen the same
694 * enctype as the ticket session key for the acceptor subkey, surely.
695 */
696
697 if ((*auth_context)->authentp->subkey != NULL) {
698 desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype;
699 }
700 desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype;
701 desired_etypes[desired_etypes_len] = ENCTYPE_NULL;
702
703 if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) {
704 if ((*auth_context)->permitted_etypes != NULL) {
705 permitted_etypes = (*auth_context)->permitted_etypes;
706 } else {
707 retval = krb5_get_permitted_enctypes(context, &permitted_etypes);
708 if (retval != 0)
709 goto cleanup;
710 }
711 permitted_etypes_len = k5_count_etypes(permitted_etypes);
712 } else {
713 permitted_etypes = NULL;
714 permitted_etypes_len = 0;
715 }
716
717 /* check if the various etypes are permitted */
718 retval = negotiate_etype(context,
719 desired_etypes, desired_etypes_len,
720 rfc4537_etypes_len,
721 permitted_etypes, permitted_etypes_len,
722 &(*auth_context)->negotiated_etype);
723 if (retval != 0)
724 goto cleanup;
725 TRACE_RD_REQ_NEGOTIATED_ETYPE(context, (*auth_context)->negotiated_etype);
726
727 assert((*auth_context)->negotiated_etype != ENCTYPE_NULL);
728
729 (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
730 if ((*auth_context)->authentp->subkey) {
731 TRACE_RD_REQ_SUBKEY(context, (*auth_context)->authentp->subkey);
732 if ((retval = krb5_k_create_key(context,
733 (*auth_context)->authentp->subkey,
734 &((*auth_context)->recv_subkey))))
735 goto cleanup;
736 retval = krb5_k_create_key(context, (*auth_context)->authentp->subkey,
737 &((*auth_context)->send_subkey));
738 if (retval) {
739 krb5_k_free_key(context, (*auth_context)->recv_subkey);
740 (*auth_context)->recv_subkey = NULL;
741 goto cleanup;
742 }
743 } else {
744 (*auth_context)->recv_subkey = 0;
745 (*auth_context)->send_subkey = 0;
746 }
747
748 if ((retval = krb5_k_create_key(context, req->ticket->enc_part2->session,
749 &((*auth_context)->key))))
750 goto cleanup;
751
752 /*
753 * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used
754 * then the default sequence number is the one's complement of the
755 * sequence number sent ot us.
756 */
757 if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) &&
758 (*auth_context)->remote_seq_number) {
759 (*auth_context)->local_seq_number ^=
760 (*auth_context)->remote_seq_number;
761 }
762
763 if (ticket)
764 if ((retval = krb5_copy_ticket(context, req->ticket, ticket)))
765 goto cleanup;
766 if (ap_req_options) {
767 *ap_req_options = req->ap_options & AP_OPTS_WIRE_MASK;
768 if (rfc4537_etypes_len != 0)
769 *ap_req_options |= AP_OPTS_ETYPE_NEGOTIATION;
770 if ((*auth_context)->negotiated_etype !=
771 krb5_k_key_enctype(context, (*auth_context)->key))
772 *ap_req_options |= AP_OPTS_USE_SUBKEY;
773 }
774
775 retval = 0;
776
777 cleanup:
778 if (desired_etypes != NULL)
779 free(desired_etypes);
780 if (permitted_etypes != NULL &&
781 permitted_etypes != (*auth_context)->permitted_etypes)
782 free(permitted_etypes);
783 if (check_valid_flag)
784 krb5_free_keyblock_contents(context, &decrypt_key);
785
786 return retval;
787 }
788
789 krb5_error_code
krb5_rd_req_decoded(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket)790 krb5_rd_req_decoded(krb5_context context, krb5_auth_context *auth_context,
791 const krb5_ap_req *req, krb5_const_principal server,
792 krb5_keytab keytab, krb5_flags *ap_req_options,
793 krb5_ticket **ticket)
794 {
795 krb5_error_code retval;
796 retval = rd_req_decoded_opt(context, auth_context,
797 req, server, keytab,
798 ap_req_options, ticket,
799 1); /* check_valid_flag */
800 return retval;
801 }
802
803 krb5_error_code
krb5_rd_req_decoded_anyflag(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket)804 krb5_rd_req_decoded_anyflag(krb5_context context,
805 krb5_auth_context *auth_context,
806 const krb5_ap_req *req,
807 krb5_const_principal server, krb5_keytab keytab,
808 krb5_flags *ap_req_options, krb5_ticket **ticket)
809 {
810 krb5_error_code retval;
811 retval = rd_req_decoded_opt(context, auth_context,
812 req, server, keytab,
813 ap_req_options, ticket,
814 0); /* don't check_valid_flag */
815 return retval;
816 }
817
818 #ifndef LEAN_CLIENT
819 static krb5_error_code
decrypt_authenticator(krb5_context context,const krb5_ap_req * request,krb5_authenticator ** authpp,int is_ap_req)820 decrypt_authenticator(krb5_context context, const krb5_ap_req *request,
821 krb5_authenticator **authpp, int is_ap_req)
822 {
823 krb5_authenticator *local_auth;
824 krb5_error_code retval;
825 krb5_data scratch;
826 krb5_keyblock *sesskey;
827
828 sesskey = request->ticket->enc_part2->session;
829
830 scratch.length = request->authenticator.ciphertext.length;
831 if (!(scratch.data = malloc(scratch.length)))
832 return(ENOMEM);
833
834 if ((retval = krb5_c_decrypt(context, sesskey,
835 is_ap_req?KRB5_KEYUSAGE_AP_REQ_AUTH:
836 KRB5_KEYUSAGE_TGS_REQ_AUTH, 0,
837 &request->authenticator, &scratch))) {
838 free(scratch.data);
839 return(retval);
840 }
841
842 #define clean_scratch() {memset(scratch.data, 0, scratch.length); \
843 free(scratch.data);}
844
845 /* now decode the decrypted stuff */
846 if (!(retval = decode_krb5_authenticator(&scratch, &local_auth)))
847 *authpp = local_auth;
848
849 clean_scratch();
850 return retval;
851 }
852 #endif
853
854 static krb5_error_code
negotiate_etype(krb5_context context,const krb5_enctype * desired_etypes,int desired_etypes_len,int mandatory_etypes_index,const krb5_enctype * permitted_etypes,int permitted_etypes_len,krb5_enctype * negotiated_etype)855 negotiate_etype(krb5_context context,
856 const krb5_enctype *desired_etypes,
857 int desired_etypes_len,
858 int mandatory_etypes_index,
859 const krb5_enctype *permitted_etypes,
860 int permitted_etypes_len,
861 krb5_enctype *negotiated_etype)
862 {
863 int i, j;
864
865 *negotiated_etype = ENCTYPE_NULL;
866
867 /* mandatory segment of desired_etypes must be permitted */
868 for (i = mandatory_etypes_index; i < desired_etypes_len; i++) {
869 krb5_boolean permitted = FALSE;
870
871 for (j = 0; j < permitted_etypes_len; j++) {
872 if (desired_etypes[i] == permitted_etypes[j]) {
873 permitted = TRUE;
874 break;
875 }
876 }
877
878 if (permitted == FALSE) {
879 char enctype_name[30];
880
881 if (krb5_enctype_to_name(desired_etypes[i], FALSE, enctype_name,
882 sizeof(enctype_name)) == 0)
883 k5_setmsg(context, KRB5_NOPERM_ETYPE,
884 _("Encryption type %s not permitted"), enctype_name);
885 return KRB5_NOPERM_ETYPE;
886 }
887 }
888
889 /*
890 * permitted_etypes is ordered from most to least preferred;
891 * find first desired_etype that matches.
892 */
893 for (j = 0; j < permitted_etypes_len; j++) {
894 for (i = 0; i < desired_etypes_len; i++) {
895 if (desired_etypes[i] == permitted_etypes[j]) {
896 *negotiated_etype = permitted_etypes[j];
897 return 0;
898 }
899 }
900 }
901
902 /*NOTREACHED*/
903 return KRB5_NOPERM_ETYPE;
904 }
905
906 static krb5_error_code
decode_etype_list(krb5_context context,const krb5_authenticator * authp,krb5_enctype ** desired_etypes,int * desired_etypes_len)907 decode_etype_list(krb5_context context,
908 const krb5_authenticator *authp,
909 krb5_enctype **desired_etypes,
910 int *desired_etypes_len)
911 {
912 krb5_error_code code;
913 krb5_authdata **ad_if_relevant = NULL;
914 krb5_authdata *etype_adata = NULL;
915 krb5_etype_list *etype_list = NULL;
916 int i, j;
917 krb5_data data;
918
919 *desired_etypes = NULL;
920
921 if (authp->authorization_data == NULL)
922 return 0;
923
924 /*
925 * RFC 4537 says that ETYPE_NEGOTIATION auth data should be wrapped
926 * in AD_IF_RELEVANT, but we handle the case where it is mandatory.
927 */
928 for (i = 0; authp->authorization_data[i] != NULL; i++) {
929 switch (authp->authorization_data[i]->ad_type) {
930 case KRB5_AUTHDATA_IF_RELEVANT:
931 code = krb5_decode_authdata_container(context,
932 KRB5_AUTHDATA_IF_RELEVANT,
933 authp->authorization_data[i],
934 &ad_if_relevant);
935 if (code != 0)
936 continue;
937
938 for (j = 0; ad_if_relevant[j] != NULL; j++) {
939 if (ad_if_relevant[j]->ad_type == KRB5_AUTHDATA_ETYPE_NEGOTIATION) {
940 etype_adata = ad_if_relevant[j];
941 break;
942 }
943 }
944 if (etype_adata == NULL) {
945 krb5_free_authdata(context, ad_if_relevant);
946 ad_if_relevant = NULL;
947 }
948 break;
949 case KRB5_AUTHDATA_ETYPE_NEGOTIATION:
950 etype_adata = authp->authorization_data[i];
951 break;
952 default:
953 break;
954 }
955 if (etype_adata != NULL)
956 break;
957 }
958
959 if (etype_adata == NULL)
960 return 0;
961
962 data.data = (char *)etype_adata->contents;
963 data.length = etype_adata->length;
964
965 code = decode_krb5_etype_list(&data, &etype_list);
966 if (code == 0) {
967 *desired_etypes = etype_list->etypes;
968 *desired_etypes_len = etype_list->length;
969 free(etype_list);
970 }
971
972 if (ad_if_relevant != NULL)
973 krb5_free_authdata(context, ad_if_relevant);
974
975 return code;
976 }
977