1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/kdc_preauth.c - Preauthentication routines for the KDC */
4 * Copyright 1995, 2003, 2007, 2009 by the Massachusetts Institute of
5 * Technology. All Rights Reserved.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * Copyright (C) 1998 by the FundsXpress, INC.
29 * All rights reserved.
31 * Export of this software from the United States of America may require
32 * a specific license from the United States Government. It is the
33 * responsibility of any person or organization contemplating export to
34 * obtain such a license before exporting.
36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37 * distribute this software and its documentation for any purpose and
38 * without fee is hereby granted, provided that the above copyright
39 * notice appear in all copies and that both that copyright notice and
40 * this permission notice appear in supporting documentation, and that
41 * the name of FundsXpress. not be used in advertising or publicity pertaining
42 * to distribution of the software without specific, written prior
43 * permission. FundsXpress makes no representations about the suitability of
44 * this software for any purpose. It is provided "as is" without express
45 * or implied warranty.
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
52 * Copyright (c) 2006-2008, Novell, Inc.
53 * All rights reserved.
55 * Redistribution and use in source and binary forms, with or without
56 * modification, are permitted provided that the following conditions are met:
58 * * Redistributions of source code must retain the above copyright notice,
59 * this list of conditions and the following disclaimer.
60 * * Redistributions in binary form must reproduce the above copyright
61 * notice, this list of conditions and the following disclaimer in the
62 * documentation and/or other materials provided with the distribution.
63 * * The copyright holder's name is not used to endorse or promote products
64 * derived from this software without specific prior written permission.
66 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
67 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
69 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
70 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76 * POSSIBILITY OF SUCH DAMAGE.
83 #include "adm_proto.h"
85 #include "pkinit_server.h"
86 #include "pkinit_cert_store.h"
87 #endif /* APPLE_PKINIT */
92 #include "../include/krb5/preauth_plugin.h"
94 typedef struct preauth_system_st {
98 krb5_kdcpreauth_moddata moddata;
99 krb5_kdcpreauth_init_fn init;
100 krb5_kdcpreauth_fini_fn fini;
101 krb5_kdcpreauth_edata_fn get_edata;
102 krb5_kdcpreauth_verify_fn verify_padata;
103 krb5_kdcpreauth_return_fn return_padata;
104 krb5_kdcpreauth_free_modreq_fn free_modreq;
108 get_etype_info(krb5_context context, krb5_kdc_req *request,
109 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
110 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
111 krb5_kdcpreauth_edata_respond_fn respond, void *arg);
114 get_etype_info2(krb5_context context, krb5_kdc_req *request,
115 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
116 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
117 krb5_kdcpreauth_edata_respond_fn respond, void *arg);
119 static krb5_error_code
120 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
121 krb5_db_entry *client,
122 krb5_kdc_req *request, krb5_kdc_rep *reply,
123 krb5_key_data *client_key,
124 krb5_keyblock *encrypting_key,
125 krb5_pa_data **send_pa,
128 static krb5_error_code
129 return_etype_info(krb5_context, krb5_pa_data *padata,
130 krb5_data *req_pkt, krb5_kdc_req *request,
131 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
132 krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
133 krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
134 krb5_kdcpreauth_modreq modreq);
136 static krb5_error_code
137 return_etype_info2(krb5_context, krb5_pa_data *padata,
138 krb5_data *req_pkt, krb5_kdc_req *request,
139 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
140 krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
141 krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
142 krb5_kdcpreauth_modreq modreq);
144 static krb5_error_code
145 return_pw_salt(krb5_context, krb5_pa_data *padata,
146 krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
147 krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
148 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
149 krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq);
153 /* PKINIT preauth support */
154 static krb5_error_code get_pkinit_edata(
155 krb5_context context,
156 krb5_kdc_req *request,
157 krb5_db_entry *client,
158 krb5_db_entry *server,
159 preauth_get_entry_data_proc get_entry_data,
160 void *pa_module_context,
161 krb5_pa_data *pa_data);
162 static krb5_error_code verify_pkinit_request(
163 krb5_context context,
164 krb5_db_entry *client,
166 krb5_kdc_req *request,
167 krb5_enc_tkt_part *enc_tkt_reply,
169 preauth_get_entry_data_proc get_entry_data,
170 void *pa_module_context,
171 void **pa_request_context,
173 krb5_authdata ***authz_data);
174 static krb5_error_code return_pkinit_response(
175 krb5_context context,
176 krb5_pa_data * padata,
177 krb5_db_entry *client,
179 krb5_kdc_req *request,
181 krb5_key_data *client_key,
182 krb5_keyblock *encrypting_key,
183 krb5_pa_data **send_pa,
184 preauth_get_entry_data_proc get_entry_data,
185 void *pa_module_context,
186 void **pa_request_context);
187 #endif /* APPLE_PKINIT */
189 static preauth_system static_preauth_systems[] = {
193 KRB5_PADATA_PK_AS_REQ,
195 NULL, /* pa_sys_context */
199 verify_pkinit_request,
200 return_pkinit_response,
201 NULL /* free_modreq */
203 #endif /* APPLE_PKINIT */
217 KRB5_PADATA_ETYPE_INFO,
228 KRB5_PADATA_ETYPE_INFO2,
240 PA_PSEUDO, /* Don't include this in the error list */
250 KRB5_PADATA_PAC_REQUEST,
262 KRB5_PADATA_SERVER_REFERRAL,
266 return_server_referral
271 #define NUM_STATIC_PREAUTH_SYSTEMS (sizeof(static_preauth_systems) / \
272 sizeof(*static_preauth_systems))
274 static preauth_system *preauth_systems;
275 static size_t n_preauth_systems;
277 /* Get all available kdcpreauth vtables and a count of preauth types they
278 * support. Return an empty list on failure. */
280 get_plugin_vtables(krb5_context context,
281 struct krb5_kdcpreauth_vtable_st **vtables_out,
282 size_t *n_tables_out, size_t *n_systems_out)
284 krb5_plugin_initvt_fn *plugins = NULL, *pl;
285 struct krb5_kdcpreauth_vtable_st *vtables;
286 size_t count, n_tables, n_systems, i;
289 *n_tables_out = *n_systems_out = 0;
291 /* Auto-register encrypted challenge and (if possible) pkinit. */
292 k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit",
294 k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
295 "encrypted_challenge",
296 kdcpreauth_encrypted_challenge_initvt);
297 k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
298 "encrypted_timestamp",
299 kdcpreauth_encrypted_timestamp_initvt);
301 if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins))
303 for (count = 0; plugins[count]; count++);
304 vtables = calloc(count + 1, sizeof(*vtables));
307 for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
308 if ((*pl)(context, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
311 for (i = 0, n_systems = 0; i < n_tables; i++) {
312 for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
315 *vtables_out = vtables;
316 *n_tables_out = n_tables;
317 *n_systems_out = n_systems;
320 k5_plugin_free_modules(context, plugins);
323 /* Make a list of realm names. The caller should free the list container but
324 * not the list elements (which are aliases into kdc_realmlist). */
325 static krb5_error_code
326 get_realm_names(const char ***list_out)
331 list = calloc(kdc_numrealms + 1, sizeof(*list));
334 for (i = 0; i < kdc_numrealms; i++)
335 list[i] = kdc_realmlist[i]->realm_name;
342 load_preauth_plugins(krb5_context context)
345 struct krb5_kdcpreauth_vtable_st *vtables = NULL, *vt;
346 size_t n_systems, n_tables, i, j;
347 krb5_kdcpreauth_moddata moddata;
348 const char **realm_names = NULL, *emsg;
351 /* Get all available kdcpreauth vtables. */
352 get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
354 /* Allocate the list of static and plugin preauth systems. */
355 n_systems += NUM_STATIC_PREAUTH_SYSTEMS;
356 preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
357 if (preauth_systems == NULL)
360 if (get_realm_names(&realm_names))
363 /* Add the static system to the list first. No static systems require
364 * initialization, so just make a direct copy. */
365 memcpy(preauth_systems, static_preauth_systems,
366 sizeof(static_preauth_systems));
368 /* Add the dynamically-loaded mechanisms to the list. */
369 n_systems = NUM_STATIC_PREAUTH_SYSTEMS;
370 for (i = 0; i < n_tables; i++) {
371 /* Try to initialize this module. */
375 ret = vt->init(context, &moddata, realm_names);
377 emsg = krb5_get_error_message(context, ret);
378 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to "
379 "initialize: %s"), vt->name, emsg);
380 krb5_free_error_message(context, emsg);
384 /* Add this module to the systems list once for each pa type. */
385 for (j = 0; vt->pa_type_list[j] > 0; j++) {
386 sys = &preauth_systems[n_systems];
387 sys->name = vt->name;
388 sys->type = vt->pa_type_list[j];
389 sys->flags = (vt->flags) ? vt->flags(context, sys->type) : 0;
390 sys->moddata = moddata;
391 sys->init = vt->init;
392 /* Only call fini once for each plugin. */
393 sys->fini = (j == 0) ? vt->fini : NULL;
394 sys->get_edata = vt->edata;
395 sys->verify_padata = vt->verify;
396 sys->return_padata = vt->return_padata;
397 sys->free_modreq = vt->free_modreq;
401 n_preauth_systems = n_systems;
402 /* Add the end-of-list marker. */
403 preauth_systems[n_systems].name = "[end]";
404 preauth_systems[n_systems].type = -1;
412 unload_preauth_plugins(krb5_context context)
416 for (i = 0; i < n_preauth_systems; i++) {
417 if (preauth_systems[i].fini)
418 preauth_systems[i].fini(context, preauth_systems[i].moddata);
420 free(preauth_systems);
421 preauth_systems = NULL;
422 n_preauth_systems = 0;
426 * The make_padata_context() function creates a space for storing any
427 * request-specific module data which will be needed by return_padata() later.
428 * Each preauth type gets a storage location of its own.
430 struct request_pa_context {
433 preauth_system *pa_system;
434 krb5_kdcpreauth_modreq modreq;
438 static krb5_error_code
439 make_padata_context(krb5_context context, void **padata_context)
442 struct request_pa_context *ret;
444 ret = malloc(sizeof(*ret));
449 ret->n_contexts = n_preauth_systems;
450 ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts);
451 if (ret->contexts == NULL) {
456 memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts);
458 for (i = 0; i < ret->n_contexts; i++) {
459 ret->contexts[i].pa_system = &preauth_systems[i];
460 ret->contexts[i].modreq = NULL;
463 *padata_context = ret;
469 * The free_padata_context function frees any context information pointers
470 * which the check_padata() function created but which weren't already cleaned
471 * up by return_padata().
474 free_padata_context(krb5_context kcontext, void *padata_context)
476 struct request_pa_context *context = padata_context;
482 for (i = 0; i < context->n_contexts; i++) {
483 sys = context->contexts[i].pa_system;
484 if (!sys->free_modreq || !context->contexts[i].modreq)
486 sys->free_modreq(kcontext, sys->moddata, context->contexts[i].modreq);
487 context->contexts[i].modreq = NULL;
490 free(context->contexts);
495 max_time_skew(krb5_context context, krb5_kdcpreauth_rock rock)
497 return context->clockskew;
500 static krb5_error_code
501 client_keys(krb5_context context, krb5_kdcpreauth_rock rock,
502 krb5_keyblock **keys_out)
504 krb5_kdc_req *request = rock->request;
505 krb5_db_entry *client = rock->client;
506 krb5_keyblock *keys, key;
507 krb5_key_data *entry_key;
510 keys = malloc(sizeof(krb5_keyblock) * (request->nktypes + 1));
514 memset(keys, 0, sizeof(krb5_keyblock) * (request->nktypes + 1));
516 for (i = 0; i < request->nktypes; i++) {
518 if (krb5_dbe_find_enctype(context, client, request->ktype[i],
519 -1, 0, &entry_key) != 0)
521 if (krb5_dbe_decrypt_key_data(context, NULL, entry_key,
534 static void free_keys(krb5_context context, krb5_kdcpreauth_rock rock,
541 for (k = keys; k->enctype != 0; k++)
542 krb5_free_keyblock_contents(context, k);
547 request_body(krb5_context context, krb5_kdcpreauth_rock rock)
549 return rock->inner_body;
552 static krb5_keyblock *
553 fast_armor(krb5_context context, krb5_kdcpreauth_rock rock)
555 return rock->rstate->armor_key;
558 static krb5_error_code
559 get_string(krb5_context context, krb5_kdcpreauth_rock rock, const char *key,
562 return krb5_dbe_get_string(context, rock->client, key, value_out);
566 free_string(krb5_context context, krb5_kdcpreauth_rock rock, char *string)
568 krb5_dbe_free_string(context, string);
572 client_entry(krb5_context context, krb5_kdcpreauth_rock rock)
578 event_context(krb5_context context, krb5_kdcpreauth_rock rock)
583 static struct krb5_kdcpreauth_callbacks_st callbacks = {
596 static krb5_error_code
597 find_pa_system(int type, preauth_system **preauth)
601 ap = preauth_systems ? preauth_systems : static_preauth_systems;
602 while ((ap->type != -1) && (ap->type != type))
605 return(KRB5_PREAUTH_BAD_TYPE);
610 /* Find a pointer to the request-specific module data for pa_sys. */
611 static krb5_error_code
612 find_modreq(preauth_system *pa_sys, struct request_pa_context *context,
613 krb5_kdcpreauth_modreq **modreq_out)
619 return KRB5KRB_ERR_GENERIC;
621 for (i = 0; i < context->n_contexts; i++) {
622 if (context->contexts[i].pa_system == pa_sys) {
623 *modreq_out = &context->contexts[i].modreq;
628 return KRB5KRB_ERR_GENERIC;
632 * Create a list of indices into the preauth_systems array, sorted by order of
636 pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type)
638 while (*pa_data != NULL) {
639 if ((*pa_data)->pa_type == pa_type)
646 sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
648 size_t i, j, k, n_repliers, n_key_replacers;
650 /* First, set up the default order. */
652 for (j = 0; j < n_preauth_systems; j++) {
653 if (preauth_systems[j].return_padata != NULL)
657 pa_order[n_repliers] = -1;
659 /* Reorder so that PA_REPLACES_KEY modules are listed first. */
660 for (i = 0; i < n_repliers; i++) {
661 /* If this module replaces the key, then it's okay to leave it where it
662 * is in the order. */
663 if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY)
665 /* If not, search for a module which does, and swap in the first one we
667 for (j = i + 1; j < n_repliers; j++) {
668 if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) {
670 pa_order[j] = pa_order[i];
677 if (request->padata != NULL) {
678 /* Now reorder the subset of modules which replace the key,
679 * bubbling those which handle pa_data types provided by the
680 * client ahead of the others.
682 for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) {
686 for (i = 0; i < n_key_replacers; i++) {
687 if (pa_list_includes(request->padata,
688 preauth_systems[pa_order[i]].type))
690 for (j = i + 1; j < n_key_replacers; j++) {
691 if (pa_list_includes(request->padata,
692 preauth_systems[pa_order[j]].type)) {
694 pa_order[j] = pa_order[i];
702 krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:");
703 for (i = 0; i < n_preauth_systems; i++) {
704 if (preauth_systems[i].return_padata != NULL)
705 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name,
706 preauth_systems[i].type);
708 krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:");
709 for (i = 0; pa_order[i] != -1; i++) {
710 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)",
711 preauth_systems[pa_order[i]].name,
712 preauth_systems[pa_order[i]].type);
717 const char *missing_required_preauth(krb5_db_entry *client,
718 krb5_db_entry *server,
719 krb5_enc_tkt_part *enc_tkt_reply)
723 * If this is the pwchange service, and the pre-auth bit is set,
724 * allow it even if the HW preauth would normally be required.
726 * Sandia national labs wanted this for some strange reason... we
727 * leave it disabled normally.
729 if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
730 isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
737 "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
738 isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
739 isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
740 isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
741 isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
744 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
745 !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
746 return "NEEDED_PREAUTH";
748 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
749 !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
750 return "NEEDED_HW_PREAUTH";
756 kdc_hint_respond_fn respond;
760 krb5_kdcpreauth_rock rock;
761 krb5_kdc_req *request;
762 krb5_pa_data ***e_data_out;
766 krb5_pa_data **pa_data, **pa_cur;
767 krb5_preauthtype pa_type;
771 hint_list_finish(struct hint_state *state, krb5_error_code code)
773 kdc_hint_respond_fn oldrespond = state->respond;
774 void *oldarg = state->arg;
777 if (state->pa_data[0] == 0) {
778 krb5_klog_syslog(LOG_INFO,
779 _("%spreauth required but hint list is empty"),
780 state->hw_only ? "hw" : "");
782 /* If we fail to get the cookie it is probably still reasonable to
783 * continue with the response. */
784 kdc_preauth_get_cookie(state->rock->rstate, state->pa_cur);
786 *state->e_data_out = state->pa_data;
787 state->pa_data = NULL;
790 krb5_free_pa_data(kdc_context, state->pa_data);
792 (*oldrespond)(oldarg);
796 hint_list_next(struct hint_state *arg);
799 finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
801 struct hint_state *state = arg;
803 kdc_active_realm = state->realm;
806 /* Include an empty value of the current type. */
807 pa = calloc(1, sizeof(*pa));
808 pa->magic = KV5M_PA_DATA;
809 pa->pa_type = state->pa_type;
811 *state->pa_cur++ = pa;
815 hint_list_next(state);
819 hint_list_next(struct hint_state *state)
821 preauth_system *ap = state->ap;
823 if (ap->type == -1) {
824 hint_list_finish(state, 0);
828 if (state->hw_only && !(ap->flags & PA_HARDWARE))
830 if (ap->flags & PA_PSEUDO)
833 state->pa_type = ap->type;
835 ap->get_edata(kdc_context, state->request, &callbacks, state->rock,
836 ap->moddata, ap->type, finish_get_edata, state);
838 finish_get_edata(state, 0, NULL);
843 hint_list_next(state);
847 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
848 krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
851 struct hint_state *state;
855 /* Allocate our state. */
856 state = calloc(1, sizeof(*state));
861 state->hw_only = isflagset(rock->client->attributes,
862 KRB5_KDB_REQUIRES_HW_AUTH);
863 state->respond = respond;
865 state->request = request;
867 state->realm = kdc_active_realm;
868 state->e_data_out = e_data_out;
870 /* Allocate two extra entries for the cookie and the terminator. */
871 state->pa_data = calloc(n_preauth_systems + 2, sizeof(krb5_pa_data *));
872 if (!state->pa_data) {
878 state->pa_cur = state->pa_data;
879 state->ap = preauth_systems;
880 hint_list_next(state);
884 * Add authorization data returned from preauth modules to the ticket
885 * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs
887 static krb5_error_code
888 add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
890 krb5_authdata **newad;
891 int oldones, newones;
894 if (enc_tkt_part == NULL || ad == NULL)
897 for (newones = 0; ad[newones] != NULL; newones++);
899 return 0; /* nothing to add */
901 if (enc_tkt_part->authorization_data == NULL)
905 enc_tkt_part->authorization_data[oldones] != NULL; oldones++);
907 newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *));
911 /* Copy any existing pointers */
912 for (i = 0; i < oldones; i++)
913 newad[i] = enc_tkt_part->authorization_data[i];
915 /* Add the new ones */
916 for (i = 0; i < newones; i++)
917 newad[oldones+i] = ad[i];
919 /* Terminate the new list */
920 newad[oldones+i] = NULL;
922 /* Free any existing list */
923 if (enc_tkt_part->authorization_data != NULL)
924 free(enc_tkt_part->authorization_data);
926 /* Install our new list */
927 enc_tkt_part->authorization_data = newad;
932 struct padata_state {
933 kdc_preauth_respond_fn respond;
937 krb5_kdcpreauth_modreq *modreq_ptr;
938 krb5_pa_data **padata;
940 krb5_context context;
941 krb5_kdcpreauth_rock rock;
943 krb5_kdc_req *request;
944 krb5_enc_tkt_part *enc_tkt_reply;
945 void **padata_context;
947 preauth_system *pa_sys;
948 krb5_pa_data **pa_e_data;
949 krb5_boolean typed_e_data_flag;
951 krb5_error_code saved_code;
953 krb5_pa_data ***e_data_out;
954 krb5_boolean *typed_e_data_out;
958 finish_check_padata(struct padata_state *state, krb5_error_code code)
960 kdc_preauth_respond_fn oldrespond;
964 oldrespond = state->respond;
968 /* Return any saved preauth e-data. */
969 *state->e_data_out = state->pa_e_data;
970 *state->typed_e_data_out = state->typed_e_data_flag;
972 krb5_free_pa_data(state->context, state->pa_e_data);
976 (*oldrespond)(oldarg, 0);
980 /* pa system was not found; we may return PREAUTH_REQUIRED later,
981 but we did not actually fail to verify the pre-auth. */
982 if (!state->pa_found) {
984 (*oldrespond)(oldarg, 0);
989 /* The following switch statement allows us
990 * to return some preauth system errors back to the client.
993 case 0: /* in case of PA-PAC-REQUEST with no PA-ENC-TIMESTAMP */
994 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
995 case KRB5KRB_AP_ERR_SKEW:
996 case KRB5KDC_ERR_PREAUTH_REQUIRED:
997 case KRB5KDC_ERR_ETYPE_NOSUPP:
999 case KRB5KDC_ERR_CLIENT_NOT_TRUSTED:
1000 case KRB5KDC_ERR_INVALID_SIG:
1001 case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
1002 case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
1003 case KRB5KDC_ERR_INVALID_CERTIFICATE:
1004 case KRB5KDC_ERR_REVOKED_CERTIFICATE:
1005 case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN:
1006 case KRB5KDC_ERR_CLIENT_NAME_MISMATCH:
1007 case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE:
1008 case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED:
1009 case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED:
1010 case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED:
1011 case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED:
1012 /* earlier drafts of what became rfc 4556 */
1013 case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
1014 case KRB5KDC_ERR_KDC_NOT_TRUSTED:
1015 case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
1016 /* This value is shared with
1017 * KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1018 /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
1019 case KRB5KDC_ERR_DISCARD:
1020 /* pkinit alg-agility */
1021 case KRB5KDC_ERR_NO_ACCEPTABLE_KDF:
1022 (*oldrespond)(oldarg, code);
1025 (*oldrespond)(oldarg, KRB5KDC_ERR_PREAUTH_FAILED);
1031 next_padata(struct padata_state *state);
1034 finish_verify_padata(void *arg, krb5_error_code code,
1035 krb5_kdcpreauth_modreq modreq, krb5_pa_data **e_data,
1036 krb5_authdata **authz_data)
1038 struct padata_state *state = arg;
1040 krb5_boolean typed_e_data_flag;
1043 kdc_active_realm = state->realm; /* Restore the realm. */
1044 *state->modreq_ptr = modreq;
1047 emsg = krb5_get_error_message(state->context, code);
1048 krb5_klog_syslog(LOG_INFO, "preauth (%s) verify failure: %s",
1049 state->pa_sys->name, emsg);
1050 krb5_free_error_message(state->context, emsg);
1052 /* Ignore authorization data returned from modules that fail */
1053 if (authz_data != NULL) {
1054 krb5_free_authdata(state->context, authz_data);
1058 typed_e_data_flag = ((state->pa_sys->flags & PA_TYPED_E_DATA) != 0);
1061 * We'll return edata from either the first PA_REQUIRED module
1062 * that fails, or the first non-PA_REQUIRED module that fails.
1063 * Hang on to edata from the first non-PA_REQUIRED module.
1064 * If we've already got one saved, simply discard this one.
1066 if (state->pa_sys->flags & PA_REQUIRED) {
1067 /* free up any previous edata we might have been saving */
1068 if (state->pa_e_data != NULL)
1069 krb5_free_pa_data(state->context, state->pa_e_data);
1070 state->pa_e_data = e_data;
1071 state->typed_e_data_flag = typed_e_data_flag;
1073 /* Make sure we use the current retval */
1075 finish_check_padata(state, code);
1077 } else if (state->pa_e_data == NULL) {
1078 /* save the first error code and e-data */
1079 state->pa_e_data = e_data;
1080 state->typed_e_data_flag = typed_e_data_flag;
1081 state->saved_code = code;
1082 } else if (e_data != NULL) {
1083 /* discard this extra e-data from non-PA_REQUIRED module */
1084 krb5_free_pa_data(state->context, e_data);
1088 krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
1091 /* Ignore any edata returned on success */
1093 krb5_free_pa_data(state->context, e_data);
1095 /* Add any authorization data to the ticket */
1096 if (authz_data != NULL) {
1097 add_authorization_data(state->enc_tkt_reply, authz_data);
1102 if (state->pa_sys->flags & PA_SUFFICIENT) {
1103 finish_check_padata(state, state->saved_code);
1112 next_padata(struct padata_state *state)
1116 state->padata = state->request->padata;
1120 if (!*state->padata) {
1121 finish_check_padata(state, state->saved_code);
1126 krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*state->padata)->pa_type);
1128 if (find_pa_system((*state->padata)->pa_type, &state->pa_sys))
1130 if (find_modreq(state->pa_sys, *state->padata_context, &state->modreq_ptr))
1133 krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", state->pa_sys->name);
1135 if (state->pa_sys->verify_padata == 0)
1139 state->pa_sys->verify_padata(state->context, state->req_pkt,
1140 state->request, state->enc_tkt_reply,
1141 *state->padata, &callbacks, state->rock,
1142 state->pa_sys->moddata, finish_verify_padata,
1151 * This routine is called to verify the preauthentication information
1154 * Returns 0 if the pre-authentication is valid, non-zero to indicate
1155 * an error code of some sort.
1159 check_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1160 krb5_data *req_pkt, krb5_kdc_req *request,
1161 krb5_enc_tkt_part *enc_tkt_reply, void **padata_context,
1162 krb5_pa_data ***e_data, krb5_boolean *typed_e_data,
1163 kdc_preauth_respond_fn respond, void *arg)
1165 struct padata_state *state;
1167 if (request->padata == 0) {
1172 if (make_padata_context(context, padata_context) != 0) {
1173 (*respond)(arg, KRB5KRB_ERR_GENERIC);
1177 state = calloc(1, sizeof(*state));
1178 if (state == NULL) {
1179 (*respond)(arg, ENOMEM);
1182 state->respond = respond;
1184 state->context = context;
1186 state->req_pkt = req_pkt;
1187 state->request = request;
1188 state->enc_tkt_reply = enc_tkt_reply;
1189 state->padata_context = padata_context;
1190 state->e_data_out = e_data;
1191 state->typed_e_data_out = typed_e_data;
1192 state->realm = kdc_active_realm;
1195 krb5_klog_syslog (LOG_DEBUG, "checking padata");
1202 * return_padata creates any necessary preauthentication
1203 * structures which should be returned by the KDC to the client
1206 return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1207 krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
1208 krb5_keyblock *encrypting_key, void **padata_context)
1210 krb5_error_code retval;
1211 krb5_pa_data ** padata;
1212 krb5_pa_data ** send_pa_list;
1213 krb5_pa_data ** send_pa;
1214 krb5_pa_data * pa = 0;
1215 krb5_pa_data null_item;
1216 preauth_system * ap;
1220 krb5_kdcpreauth_modreq *modreq_ptr;
1221 krb5_boolean key_modified;
1222 krb5_keyblock original_key;
1223 if ((!*padata_context) &&
1224 (make_padata_context(context, padata_context) != 0)) {
1225 return KRB5KRB_ERR_GENERIC;
1228 for (ap = preauth_systems; ap->type != -1; ap++) {
1229 if (ap->return_padata)
1233 if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
1235 if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
1239 sort_pa_order(context, request, pa_order);
1241 retval = krb5_copy_keyblock_contents(context, encrypting_key,
1248 key_modified = FALSE;
1249 null_item.contents = NULL;
1250 null_item.length = 0;
1251 send_pa = send_pa_list;
1254 for (pa_type = pa_order; *pa_type != -1; pa_type++) {
1255 ap = &preauth_systems[*pa_type];
1257 if (original_key.enctype != encrypting_key->enctype)
1258 key_modified = TRUE;
1260 if (original_key.length != encrypting_key->length)
1261 key_modified = TRUE;
1263 if (memcmp(original_key.contents, encrypting_key->contents,
1264 original_key.length) != 0)
1265 key_modified = TRUE;
1266 if (key_modified && (ap->flags & PA_REPLACES_KEY))
1268 if (ap->return_padata == 0)
1270 if (find_modreq(ap, *padata_context, &modreq_ptr))
1273 null_item.pa_type = ap->type;
1274 if (request->padata) {
1275 for (padata = request->padata; *padata; padata++) {
1276 if ((*padata)->pa_type == ap->type) {
1282 retval = ap->return_padata(context, pa, req_pkt, request, reply,
1283 encrypting_key, send_pa, &callbacks, rock,
1284 ap->moddata, *modreq_ptr);
1295 if (send_pa_list[0]) {
1296 reply->padata = send_pa_list;
1301 krb5_free_keyblock_contents(context, &original_key);
1304 krb5_free_pa_data(context, send_pa_list);
1310 request_contains_enctype(krb5_context context, const krb5_kdc_req *request,
1311 krb5_enctype enctype)
1314 for (i =0; i < request->nktypes; i++)
1315 if (request->ktype[i] == enctype)
1320 static krb5_error_code
1321 _make_etype_info_entry(krb5_context context,
1322 krb5_principal client_princ, krb5_key_data *client_key,
1323 krb5_enctype etype, krb5_etype_info_entry **entry_out,
1326 krb5_error_code retval;
1327 krb5_int16 salttype;
1328 krb5_data *salt = NULL;
1329 krb5_etype_info_entry *entry = NULL;
1332 entry = malloc(sizeof(*entry));
1336 entry->magic = KV5M_ETYPE_INFO_ENTRY;
1337 entry->etype = etype;
1338 entry->length = KRB5_ETYPE_NO_SALT;
1340 entry->s2kparams = empty_data();
1341 retval = krb5_dbe_compute_salt(context, client_key, client_princ,
1345 if (etype_info2 && salttype == KRB5_KDB_SALTTYPE_AFS3) {
1347 case ENCTYPE_DES_CBC_CRC:
1348 case ENCTYPE_DES_CBC_MD4:
1349 case ENCTYPE_DES_CBC_MD5:
1350 retval = alloc_data(&entry->s2kparams, 1);
1353 entry->s2kparams.data[0] = 1;
1360 entry->length = salt->length;
1361 entry->salt = (unsigned char *)salt->data;
1368 krb5_free_data_contents(context, &entry->s2kparams);
1370 krb5_free_data(context, salt);
1374 /* Create etype information for a client for the preauth-required hint list,
1375 * for either etype-info or etype-info2. */
1377 etype_info_helper(krb5_context context, krb5_kdc_req *request,
1378 krb5_db_entry *client, krb5_preauthtype pa_type,
1379 krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1381 krb5_error_code retval;
1382 krb5_pa_data *pa = NULL;
1383 krb5_etype_info_entry **entry = NULL;
1384 krb5_data *scratch = NULL;
1385 krb5_key_data *client_key;
1386 krb5_enctype db_etype;
1387 int i = 0, start = 0, seen_des = 0;
1388 int etype_info2 = (pa_type == KRB5_PADATA_ETYPE_INFO2);
1390 entry = k5alloc((client->n_key_data * 2 + 1) * sizeof(*entry), &retval);
1396 retval = krb5_dbe_search_enctype(context, client, &start, -1,
1397 -1, 0, &client_key);
1398 if (retval == KRB5_KDB_NO_MATCHING_KEY)
1402 db_etype = client_key->key_data_type[0];
1403 if (db_etype == ENCTYPE_DES_CBC_MD4)
1404 db_etype = ENCTYPE_DES_CBC_MD5;
1406 if (request_contains_enctype(context, request, db_etype)) {
1407 assert(etype_info2 ||
1408 !enctype_requires_etype_info_2(db_etype));
1409 retval = _make_etype_info_entry(context, client->princ, client_key,
1410 db_etype, &entry[i], etype_info2);
1417 * If there is a des key in the kdb, try the "similar" enctypes,
1418 * avoid duplicate entries.
1422 case ENCTYPE_DES_CBC_MD5:
1423 db_etype = ENCTYPE_DES_CBC_CRC;
1425 case ENCTYPE_DES_CBC_CRC:
1426 db_etype = ENCTYPE_DES_CBC_MD5;
1432 if (request_contains_enctype(context, request, db_etype)) {
1433 retval = _make_etype_info_entry(context, client->princ,
1434 client_key, db_etype,
1435 &entry[i], etype_info2);
1445 retval = encode_krb5_etype_info2(entry, &scratch);
1447 retval = encode_krb5_etype_info(entry, &scratch);
1450 pa = k5alloc(sizeof(*pa), &retval);
1453 pa->magic = KV5M_PA_DATA;
1454 pa->pa_type = pa_type;
1455 pa->contents = (unsigned char *)scratch->data;
1456 pa->length = scratch->length;
1457 scratch->data = NULL;
1460 krb5_free_etype_info(context, entry);
1461 krb5_free_data(context, scratch);
1462 (*respond)(arg, retval, pa);
1466 get_etype_info(krb5_context context, krb5_kdc_req *request,
1467 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1468 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
1469 krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1473 for (i=0; i < request->nktypes; i++) {
1474 if (enctype_requires_etype_info_2(request->ktype[i])) {
1475 /* Requestor understands etype-info2, so don't send etype-info. */
1476 (*respond)(arg, KRB5KDC_ERR_PADATA_TYPE_NOSUPP, NULL);
1481 etype_info_helper(context, request, rock->client, pa_type, respond, arg);
1485 get_etype_info2(krb5_context context, krb5_kdc_req *request,
1486 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1487 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
1488 krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1490 etype_info_helper(context, request, rock->client, pa_type, respond, arg);
1493 static krb5_error_code
1494 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
1495 krb5_db_entry *client,
1496 krb5_kdc_req *request, krb5_kdc_rep *reply,
1497 krb5_key_data *client_key,
1498 krb5_keyblock *encrypting_key,
1499 krb5_pa_data **send_pa,
1503 krb5_error_code retval;
1504 krb5_pa_data *tmp_padata;
1505 krb5_etype_info_entry **entry = NULL;
1506 krb5_data *scratch = NULL;
1509 * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1513 for (i = 0; i < request->nktypes; i++) {
1514 if (enctype_requires_etype_info_2(request->ktype[i])) {
1521 tmp_padata = malloc( sizeof(krb5_pa_data));
1522 if (tmp_padata == NULL)
1525 tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
1527 tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO;
1529 entry = malloc(2 * sizeof(krb5_etype_info_entry *));
1530 if (entry == NULL) {
1536 retval = _make_etype_info_entry(context, client->princ, client_key,
1537 encrypting_key->enctype, entry,
1543 retval = encode_krb5_etype_info2(entry, &scratch);
1545 retval = encode_krb5_etype_info(entry, &scratch);
1549 tmp_padata->contents = (krb5_octet *)scratch->data;
1550 tmp_padata->length = scratch->length;
1551 *send_pa = tmp_padata;
1553 /* For cleanup - we no longer own the contents of the krb5_data
1554 * only to pointer to the krb5_data
1560 krb5_free_etype_info(context, entry);
1566 krb5_free_data(context, scratch);
1570 static krb5_error_code
1571 return_etype_info2(krb5_context context, krb5_pa_data * padata,
1572 krb5_data *req_pkt, krb5_kdc_req *request,
1573 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
1574 krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
1575 krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
1576 krb5_kdcpreauth_modreq modreq)
1578 return etype_info_as_rep_helper(context, padata, rock->client, request,
1579 reply, rock->client_key, encrypting_key,
1584 static krb5_error_code
1585 return_etype_info(krb5_context context, krb5_pa_data *padata,
1586 krb5_data *req_pkt, krb5_kdc_req *request,
1587 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
1588 krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
1589 krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
1590 krb5_kdcpreauth_modreq modreq)
1592 return etype_info_as_rep_helper(context, padata, rock->client, request,
1593 reply, rock->client_key, encrypting_key,
1597 static krb5_error_code
1598 return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
1599 krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
1600 krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1601 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1602 krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
1604 krb5_error_code retval;
1605 krb5_pa_data * padata;
1606 krb5_data * salt = NULL;
1607 krb5_int16 salttype;
1608 krb5_key_data * client_key = rock->client_key;
1611 for (i = 0; i < request->nktypes; i++) {
1612 if (enctype_requires_etype_info_2(request->ktype[i]))
1615 retval = krb5_dbe_compute_salt(context, client_key, request->client,
1620 padata = k5alloc(sizeof(*padata), &retval);
1623 padata->magic = KV5M_PA_DATA;
1625 if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
1626 padata->contents = k5alloc(salt->length + 1, &retval);
1627 if (padata->contents == NULL)
1629 memcpy(padata->contents, salt->data, salt->length);
1630 padata->pa_type = KRB5_PADATA_AFS3_SALT;
1631 padata->contents[salt->length] = '\0';
1632 padata->length = salt->length + 1;
1634 padata->pa_type = KRB5_PADATA_PW_SALT;
1635 padata->length = salt->length;
1636 padata->contents = (krb5_octet *)salt->data;
1645 krb5_free_data(context, salt);
1652 /* PKINIT preauth support */
1653 #define PKINIT_DEBUG 0
1655 #define kdcPkinitDebug(args...) printf(args)
1657 #define kdcPkinitDebug(args...)
1661 * get_edata() - our only job is to determine whether this KDC is capable of
1662 * performing PKINIT. We infer that from the presence or absence of any
1665 static krb5_error_code get_pkinit_edata(
1666 krb5_context context,
1667 krb5_kdc_req *request,
1668 krb5_db_entry *client,
1669 krb5_db_entry *server,
1670 preauth_get_entry_data_proc pkinit_get_entry_data,
1671 void *pa_module_context,
1672 krb5_pa_data *pa_data)
1674 krb5_pkinit_signing_cert_t cert = NULL;
1675 krb5_error_code err = krb5_pkinit_get_kdc_cert(0, NULL, NULL, &cert);
1677 kdcPkinitDebug("get_pkinit_edata: kdc cert %s\n", err ? "NOT FOUND" : "FOUND");
1679 krb5_pkinit_release_cert(cert);
1685 * This is 0 only for testing until the KDC DB contains
1686 * the hash of the client cert
1688 #define REQUIRE_CLIENT_CERT_MATCH 1
1690 static krb5_error_code verify_pkinit_request(
1691 krb5_context context,
1692 krb5_db_entry *client,
1694 krb5_kdc_req *request,
1695 krb5_enc_tkt_part *enc_tkt_reply,
1697 preauth_get_entry_data_proc pkinit_get_entry_data,
1698 void *pa_module_context,
1699 void **pa_request_context,
1701 krb5_authdata ***authz_data)
1703 krb5_error_code krtn;
1705 krb5_data *der_req = NULL;
1706 krb5_boolean valid_cksum;
1707 char *cert_hash = NULL;
1708 unsigned cert_hash_len;
1710 unsigned cert_match = 0;
1711 krb5_keyblock decrypted_key, *mkey_ptr;
1713 /* the data we get from the AS-REQ */
1714 krb5_timestamp client_ctime = 0;
1715 krb5_ui_4 client_cusec = 0;
1716 krb5_timestamp kdc_ctime = 0;
1717 krb5_int32 kdc_cusec = 0;
1718 krb5_ui_4 nonce = 0;
1719 krb5_checksum pa_cksum;
1720 krb5int_cert_sig_status cert_sig_status;
1721 krb5_data client_cert = {0, 0, NULL};
1723 krb5_kdc_req *tmp_as_req = NULL;
1725 kdcPkinitDebug("verify_pkinit_request\n");
1727 decrypted_key.contents = NULL;
1728 pa_data.data = (char *)data->contents;
1729 pa_data.length = data->length;
1730 krtn = krb5int_pkinit_as_req_parse(context, &pa_data,
1731 &client_ctime, &client_cusec,
1734 NULL, NULL,/* num_cms_types, cms_types */
1735 &client_cert, /* signer_cert */
1736 /* remaining fields unused (for now) */
1737 NULL, NULL,/* num_all_certs, all_certs */
1738 NULL, NULL,/* num_trusted_CAs, trusted_CAs */
1739 NULL); /* kdc_cert */
1741 kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
1746 if(cert_sig_status != pki_cs_good) {
1747 kdcPkinitDebug("verify_pkinit_request: cert_sig_status %d\n",
1748 (int)cert_sig_status);
1750 #endif /* PKINIT_DEBUG */
1753 * Verify signature and cert.
1754 * FIXME: The spec calls for an e-data with error-specific type to be
1755 * returned on error here. TD_TRUSTED_CERTIFIERS
1756 * to be returned to the client here. There is no way for a preauth
1757 * module to pass back e-data to process_as_req at this time. We
1758 * might want to add such capability via an out param to check_padata
1759 * and to its callees.
1761 switch(cert_sig_status) {
1764 case pki_cs_sig_verify_fail:
1766 krtn = KDC_ERR_INVALID_SIG;
1768 case pki_cs_no_root:
1769 case pki_cs_unknown_root:
1770 case pki_cs_untrusted:
1772 * Can't verify to known root.
1773 * e-data TD_TRUSTED_CERTIFIERS
1775 kdcPkinitDebug("verify_pkinit_request: KDC_ERR_CANT_VERIFY_CERTIFICATE\n");
1776 krtn = KDC_ERR_CANT_VERIFY_CERTIFICATE;
1778 case pki_cs_bad_leaf:
1779 case pki_cs_expired:
1780 case pki_cs_not_valid_yet:
1782 * Problems with client cert itself.
1783 * e-data type TD_INVALID_CERTIFICATES
1785 krtn = KDC_ERR_INVALID_CERTIFICATE;
1787 case pki_cs_revoked:
1788 /* e-data type TD-INVALID-CERTIFICATES */
1789 krtn = KDC_ERR_REVOKED_CERTIFICATE;
1791 case pki_bad_key_use:
1792 krtn = KDC_ERR_INCONSISTENT_KEY_PURPOSE;
1795 case pki_bad_digest:
1796 /* undefined (explicitly!) e-data */
1797 krtn = KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1800 case pki_cs_other_err:
1802 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1806 krtn = krb5_us_timeofday(context, &kdc_ctime, &kdc_cusec);
1810 if (labs(kdc_ctime - client_ctime) > context->clockskew) {
1811 kdcPkinitDebug("verify_pkinit_request: clock skew violation client %d svr %d\n",
1812 (int)client_ctime, (int)kdc_ctime);
1813 krtn = KRB5KRB_AP_ERR_SKEW;
1818 * The KDC may have modified the request after decoding it.
1819 * We need to compute the checksum on the data that
1820 * came from the client. Therefore, we use the original
1823 krtn = decode_krb5_as_req(req_pkt, &tmp_as_req);
1825 kdcPkinitDebug("decode_krb5_as_req returned %d\n", (int)krtn);
1829 /* calculate and compare checksum */
1830 krtn = encode_krb5_kdc_req_body(tmp_as_req, &der_req);
1832 kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
1835 krtn = krb5_c_verify_checksum(context, NULL, 0, der_req,
1836 &pa_cksum, &valid_cksum);
1838 kdcPkinitDebug("krb5_c_verify_checksum returned %d\n", (int)krtn);
1842 kdcPkinitDebug("verify_pkinit_request: checksum error\n");
1843 krtn = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1847 #if REQUIRE_CLIENT_CERT_MATCH
1848 /* look up in the KDB to ensure correct client/cert binding */
1849 cert_hash = krb5_pkinit_cert_hash_str(&client_cert);
1850 if(cert_hash == NULL) {
1854 cert_hash_len = strlen(cert_hash);
1855 for(key_dex=0; key_dex<client->n_key_data; key_dex++) {
1856 krb5_key_data *key_data = &client->key_data[key_dex];
1857 kdcPkinitDebug("--- key %u type[0] %u length[0] %u type[1] %u length[1] %u\n",
1859 key_data->key_data_type[0], key_data->key_data_length[0],
1860 key_data->key_data_type[1], key_data->key_data_length[1]);
1861 if(key_data->key_data_type[1] != KRB5_KDB_SALTTYPE_CERTHASH) {
1866 * Unfortunately this key is stored encrypted even though it's
1869 krtn = krb5_dbe_decrypt_key_data(context, NULL, key_data,
1870 &decrypted_key, NULL);
1872 kdcPkinitDebug("verify_pkinit_request: error decrypting cert hash block\n");
1875 if((decrypted_key.contents != NULL) &&
1876 (cert_hash_len == decrypted_key.length) &&
1877 !memcmp(decrypted_key.contents, cert_hash, cert_hash_len)) {
1882 if(decrypted_key.contents) {
1883 krb5_free_keyblock_contents(context, &decrypted_key);
1886 kdcPkinitDebug("verify_pkinit_request: client cert does not match\n");
1887 krtn = KDC_ERR_CLIENT_NOT_TRUSTED;
1890 #endif /* REQUIRE_CLIENT_CERT_MATCH */
1892 setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
1895 if(pa_cksum.contents) {
1896 free(pa_cksum.contents);
1899 krb5_free_kdc_req(context, tmp_as_req);
1902 krb5_free_data(context, der_req);
1907 if(client_cert.data) {
1908 free(client_cert.data);
1910 kdcPkinitDebug("verify_pkinit_request: returning %d\n", (int)krtn);
1914 static krb5_error_code return_pkinit_response(
1915 krb5_context context,
1916 krb5_pa_data * padata,
1917 krb5_db_entry *client,
1919 krb5_kdc_req *request,
1920 krb5_kdc_rep *reply,
1921 krb5_key_data *client_key,
1922 krb5_keyblock *encrypting_key,
1923 krb5_pa_data **send_pa,
1924 preauth_get_entry_data_proc pkinit_get_entry_data,
1925 void *pa_module_context,
1926 void **pa_request_context)
1928 krb5_error_code krtn;
1930 krb5_pkinit_signing_cert_t signing_cert = NULL;
1931 krb5_checksum as_req_checksum = {0};
1932 krb5_data *encoded_as_req = NULL;
1933 krb5int_algorithm_id *cms_types = NULL;
1934 krb5_ui_4 num_cms_types = 0;
1936 /* the data we get from the AS-REQ */
1937 krb5_ui_4 nonce = 0;
1938 krb5_data client_cert = {0};
1941 * Trusted CA list and specific KC cert optionally obtained via
1942 * krb5int_pkinit_as_req_parse(). All are DER-encoded
1943 * issuerAndSerialNumbers.
1945 krb5_data *trusted_CAs = NULL;
1946 krb5_ui_4 num_trusted_CAs;
1947 krb5_data kdc_cert = {0};
1949 if (padata == NULL) {
1950 /* Client has to send us something */
1954 kdcPkinitDebug("return_pkinit_response\n");
1955 pa_data.data = (char *)padata->contents;
1956 pa_data.length = padata->length;
1959 * We've already verified; just obtain the fields we need to create a response
1961 krtn = krb5int_pkinit_as_req_parse(context,
1963 NULL, NULL, &nonce, /* ctime, cusec, nonce */
1964 NULL, NULL, /* pa_cksum, cert_status */
1965 &num_cms_types, &cms_types,
1966 &client_cert, /* signer_cert: we encrypt for this */
1967 /* remaining fields unused (for now) */
1968 NULL, NULL, /* num_all_certs, all_certs */
1969 &num_trusted_CAs, &trusted_CAs,
1972 kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
1976 if(client_cert.data == NULL) {
1977 kdcPkinitDebug("pa_pk_as_req_parse failed to give a client_cert; aborting.\n");
1978 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1982 if(krb5_pkinit_get_kdc_cert(num_trusted_CAs, trusted_CAs,
1983 (kdc_cert.data ? &kdc_cert : NULL),
1986 * Since get_pkinit_edata was able to obtain *some* KDC cert,
1987 * this means that we can't satisfy the client's requirement.
1988 * FIXME - particular error status for this?
1990 kdcPkinitDebug("return_pkinit_response: NO appropriate signing cert!\n");
1991 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1996 * Cook up keyblock for caller and for outgoing AS-REP.
1997 * FIXME how much is known to be valid about encrypting_key?
1998 * Will encrypting_key->enctype always be valid here? Seems that
1999 * if we allow for clients without a shared secret (i.e. preauth
2000 * by PKINIT only) there won't be a valid encrypting_key set up
2003 krb5_free_keyblock_contents(context, encrypting_key);
2004 krb5_c_make_random_key(context, encrypting_key->enctype, encrypting_key);
2006 /* calculate checksum of incoming AS-REQ */
2007 krtn = encode_krb5_as_req(request, &encoded_as_req);
2009 kdcPkinitDebug("encode_krb5_as_req returned %d; PKINIT aborting.\n", (int)krtn);
2012 krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
2013 encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
2014 encoded_as_req, &as_req_checksum);
2020 * FIXME: here we assume that the client has one cert - the one that
2021 * signed the AuthPack in the request (and that we therefore obtained from
2022 * krb5int_pkinit_as_req_parse()), and the one we're using to encrypt the
2023 * ReplyKeyPack with here. This may need rethinking.
2025 krtn = krb5int_pkinit_as_rep_create(context,
2026 encrypting_key, &as_req_checksum,
2029 num_cms_types, cms_types,
2030 num_trusted_CAs, trusted_CAs,
2031 (kdc_cert.data ? &kdc_cert : NULL),
2034 kdcPkinitDebug("pa_pk_as_rep_create returned %d; PKINIT aborting.\n",
2039 *send_pa = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
2040 if(*send_pa == NULL) {
2045 (*send_pa)->magic = KV5M_PA_DATA;
2046 (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
2047 (*send_pa)->length = pa_data.length;
2048 (*send_pa)->contents = (krb5_octet *)pa_data.data;
2052 fprintf(stderr, "return_pkinit_response: SUCCESS\n");
2053 fprintf(stderr, "nonce 0x%x enctype %d keydata %02x %02x %02x %02x...\n",
2054 (int)nonce, (int)encrypting_key->enctype,
2055 encrypting_key->contents[0], encrypting_key->contents[1],
2056 encrypting_key->contents[2], encrypting_key->contents[3]);
2060 /* all of this was allocd by krb5int_pkinit_as_req_parse() */
2062 krb5_pkinit_release_cert(signing_cert);
2066 krb5int_algorithm_id *alg_id;
2068 for(dex=0; dex<num_cms_types; dex++) {
2069 alg_id = &cms_types[dex];
2070 if(alg_id->algorithm.data) {
2071 free(alg_id->algorithm.data);
2073 if(alg_id->parameters.data) {
2074 free(alg_id->parameters.data);
2081 for(dex=0; dex<num_trusted_CAs; dex++) {
2082 free(trusted_CAs[dex].data);
2087 free(kdc_cert.data);
2089 if(client_cert.data) {
2090 free(client_cert.data);
2092 if(encoded_as_req) {
2093 krb5_free_data(context, encoded_as_req);
2098 #endif /* APPLE_PKINIT */
2101 * Returns TRUE if the PAC should be included
2104 include_pac_p(krb5_context context, krb5_kdc_req *request)
2106 krb5_error_code code;
2107 krb5_pa_data **padata;
2108 krb5_boolean retval = TRUE; /* default is to return PAC */
2110 krb5_pa_pac_req *req = NULL;
2112 if (request->padata == NULL) {
2116 for (padata = request->padata; *padata != NULL; padata++) {
2117 if ((*padata)->pa_type == KRB5_PADATA_PAC_REQUEST) {
2118 data.data = (char *)(*padata)->contents;
2119 data.length = (*padata)->length;
2121 code = decode_krb5_pa_pac_req(&data, &req);
2123 retval = req->include_pac;
2124 krb5_free_pa_pac_req(context, req);
2134 static krb5_error_code
2135 return_referral_enc_padata( krb5_context context,
2136 krb5_enc_kdc_rep_part *reply,
2137 krb5_db_entry *server)
2139 krb5_error_code code;
2140 krb5_tl_data tl_data;
2141 krb5_pa_data pa_data;
2143 tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA;
2144 code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
2145 if (code || tl_data.tl_data_length == 0)
2148 pa_data.magic = KV5M_PA_DATA;
2149 pa_data.pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
2150 pa_data.length = tl_data.tl_data_length;
2151 pa_data.contents = tl_data.tl_data_contents;
2152 return add_pa_data_element(context, &pa_data, &reply->enc_padata, TRUE);
2156 return_enc_padata(krb5_context context, krb5_data *req_pkt,
2157 krb5_kdc_req *request, krb5_keyblock *reply_key,
2158 krb5_db_entry *server, krb5_enc_kdc_rep_part *reply_encpart,
2159 krb5_boolean is_referral)
2161 krb5_error_code code = 0;
2162 /* This should be initialized and only used for Win2K compat and other
2163 * specific standardized uses such as FAST negotiation. */
2164 assert(reply_encpart->enc_padata == NULL);
2166 code = return_referral_enc_padata(context, reply_encpart, server);
2170 code = kdc_handle_protected_negotiation(req_pkt, request, reply_key,
2171 &reply_encpart->enc_padata);
2174 /*Add potentially other enc_padata providers*/
2181 static krb5_error_code return_server_referral(krb5_context context,
2182 krb5_pa_data * padata,
2183 krb5_db_entry *client,
2184 krb5_db_entry *server,
2185 krb5_kdc_req *request,
2186 krb5_kdc_rep *reply,
2187 krb5_key_data *client_key,
2188 krb5_keyblock *encrypting_key,
2189 krb5_pa_data **send_pa)
2191 krb5_error_code code;
2192 krb5_tl_data tl_data;
2193 krb5_pa_data *pa_data;
2194 krb5_enc_data enc_data;
2196 krb5_data *enc_pa_data;
2200 tl_data.tl_data_type = KRB5_TL_SERVER_REFERRAL;
2202 code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
2203 if (code || tl_data.tl_data_length == 0)
2204 return 0; /* no server referrals to return */
2206 plain.length = tl_data.tl_data_length;
2207 plain.data = tl_data.tl_data_contents;
2209 /* Encrypt ServerReferralData */
2210 code = krb5_encrypt_helper(context, encrypting_key,
2211 KRB5_KEYUSAGE_PA_SERVER_REFERRAL_DATA,
2216 /* Encode ServerReferralData into PA-SERVER-REFERRAL-DATA */
2217 code = encode_krb5_enc_data(&enc_data, &enc_pa_data);
2219 krb5_free_data_contents(context, &enc_data.ciphertext);
2223 krb5_free_data_contents(context, &enc_data.ciphertext);
2225 /* Return PA-SERVER-REFERRAL-DATA */
2226 pa_data = (krb5_pa_data *)malloc(sizeof(*pa_data));
2227 if (pa_data == NULL) {
2228 krb5_free_data(context, enc_pa_data);
2232 pa_data->magic = KV5M_PA_DATA;
2233 pa_data->pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
2234 pa_data->length = enc_pa_data->length;
2235 pa_data->contents = enc_pa_data->data;
2237 free(enc_pa_data); /* don't free contents */