xref: /freebsd/crypto/krb5/src/lib/krb5/krb/rd_req_dec.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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