1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1995, 2003, 2008 by the Massachusetts Institute of Technology. All
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
28 * This file contains routines for establishing, verifying, and any other
29 * necessary functions, for utilizing the pre-authentication field of the
30 * kerberos kdc request, with various hardware/software verification devices.
35 #include "pkinit_client.h"
36 #include "pkinit_cert_store.h"
37 #endif /* APPLE_PKINIT */
39 #include <krb5/preauth_plugin.h>
40 #include "int-proto.h"
47 /* This structure lets us keep track of all of the modules which are loaded,
48 * turning the list of modules and their lists of implemented preauth types
49 * into a single list which we can walk easily. */
50 struct krb5_preauth_context_st {
52 struct krb5_preauth_context_module_st {
53 /* Which of the possibly more than one preauth types which the
54 * module supports we're using at this point in the list. */
55 krb5_preauthtype pa_type;
56 /* Encryption types which the client claims to support -- we
57 * copy them directly into the krb5_kdc_req structure during
58 * krb5_preauth_prepare_request(). */
59 krb5_enctype *enctypes;
60 /* The plugin's module data and a function to clear it. */
61 krb5_clpreauth_moddata moddata;
62 krb5_clpreauth_fini_fn client_fini;
63 /* The module's table, and some of its members, copied here for
64 * convenience when we populated the list. */
67 krb5_clpreauth_process_fn client_process;
68 krb5_clpreauth_tryagain_fn client_tryagain;
69 krb5_clpreauth_supply_gic_opts_fn client_supply_gic_opts;
70 krb5_clpreauth_request_init_fn client_req_init;
71 krb5_clpreauth_request_fini_fn client_req_fini;
72 /* The per-request context which the client_req_init() function
73 * might allocate, which we'll need to clean up later by
74 * calling the client_req_fini() function. */
75 krb5_clpreauth_modreq modreq;
76 /* A pointer to the request_context pointer. All modules within
77 * a plugin will point at the request_context of the first
78 * module within the plugin. */
79 krb5_clpreauth_modreq *modreq_p;
83 typedef krb5_error_code (*pa_function)(krb5_context,
84 krb5_kdc_req *request,
85 krb5_pa_data *in_padata,
86 krb5_pa_data **out_padata,
87 krb5_data *salt, krb5_data *s2kparams,
89 krb5_keyblock *as_key,
90 krb5_prompter_fct prompter_fct,
92 krb5_gic_get_as_key_fct gak_fct,
95 typedef struct _pa_types_t {
96 krb5_preauthtype type;
101 /* Create the per-krb5_context context. This means loading the modules
102 * if we haven't done that yet (applications which never obtain initial
103 * credentials should never hit this routine), breaking up the module's
104 * list of support pa_types so that we can iterate over the modules more
105 * easily, and copying over the relevant parts of the module's table. */
107 krb5_init_preauth_context(krb5_context kcontext)
109 int n_tables, n_modules, i, count;
110 krb5_plugin_initvt_fn *plugins = NULL, *pl;
111 struct krb5_clpreauth_vtable_st *vtables = NULL, *vt;
112 struct krb5_preauth_context_module_st *mod;
113 krb5_preauth_context *context = NULL;
114 krb5_clpreauth_moddata moddata;
115 krb5_preauthtype pa_type, *pat;
117 krb5_clpreauth_modreq *rcpp;
119 /* Only do this once for each krb5_context */
120 if (kcontext->preauth_context != NULL)
123 /* Auto-register encrypted challenge and (if possible) pkinit. */
124 k5_plugin_register_dyn(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "pkinit",
126 k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH,
127 "encrypted_challenge",
128 clpreauth_encrypted_challenge_initvt);
130 /* Get all available clpreauth vtables. */
131 if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins))
133 for (count = 0; plugins[count] != NULL; count++);
134 vtables = calloc(count, sizeof(*vtables));
137 for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
138 if ((*pl)(kcontext, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
142 /* Count how many modules we ended up loading, and how many preauth
143 * types we may claim to support as a result. */
145 for (i = 0; i < n_tables; i++) {
146 for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
150 /* Allocate the space we need. */
151 context = malloc(sizeof(*context));
154 context->modules = calloc(n_modules, sizeof(*context->modules));
155 if (context->modules == NULL)
158 /* fill in the structure */
160 for (i = 0; i < n_tables; i++) {
162 if ((vt->pa_type_list != NULL) && (vt->process != NULL)) {
164 if (vt->init != NULL && vt->init(kcontext, &moddata) != 0) {
166 fprintf(stderr, "init err, skipping module \"%s\"\n",
173 for (pat = vt->pa_type_list, first = TRUE; *pat > 0;
174 pat++, first = FALSE) {
176 mod = &context->modules[n_modules];
177 mod->pa_type = pa_type;
178 mod->enctypes = vt->enctype_list;
179 mod->moddata = moddata;
180 /* Only call client_fini once per plugin */
182 mod->client_fini = vt->fini;
184 mod->client_fini = NULL;
185 mod->name = vt->name;
186 mod->flags = (*vt->flags)(kcontext, pa_type);
188 mod->client_process = vt->process;
189 mod->client_tryagain = vt->tryagain;
190 mod->client_supply_gic_opts = first ? vt->gic_opts : NULL;
193 * Only call request_init and request_fini once per plugin.
194 * Only the first module within each plugin will ever
195 * have request_context filled in. Every module within
196 * the plugin will have its request_context_pp pointing
197 * to that entry's request_context. That way all the
198 * modules within the plugin share the same request_context
201 mod->client_req_init = vt->request_init;
202 mod->client_req_fini = vt->request_fini;
205 mod->client_req_init = NULL;
206 mod->client_req_fini = NULL;
208 mod->modreq_p = rcpp;
210 fprintf(stderr, "init module \"%s\", pa_type %d, flag %d\n",
211 mod->name, mod->pa_type, mod->flags);
217 context->n_modules = n_modules;
219 /* Place the constructed preauth context into the krb5 context. */
220 kcontext->preauth_context = context;
225 free(context->modules);
227 k5_plugin_free_modules(kcontext, plugins);
231 /* Zero the use counts for the modules herein. Usually used before we
232 * start processing any data from the server, at which point every module
233 * will again be able to take a crack at whatever the server sent. */
235 krb5_clear_preauth_context_use_counts(krb5_context context)
238 if (context->preauth_context != NULL) {
239 for (i = 0; i < context->preauth_context->n_modules; i++) {
240 context->preauth_context->modules[i].use_count = 0;
246 /* Free the per-krb5_context preauth_context. This means clearing any
247 * plugin-specific context which may have been created, and then
248 * freeing the context itself. */
250 krb5_free_preauth_context(krb5_context context)
253 struct krb5_preauth_context_module_st *mod;
255 if (context == NULL || context->preauth_context == NULL)
257 for (i = 0; i < context->preauth_context->n_modules; i++) {
258 mod = &context->preauth_context->modules[i];
259 if (mod->client_fini != NULL)
260 mod->client_fini(context, mod->moddata);
261 zap(mod, sizeof(*mod));
263 free(context->preauth_context->modules);
264 free(context->preauth_context);
265 context->preauth_context = NULL;
268 /* Initialize the per-AS-REQ context. This means calling the client_req_init
269 * function to give the plugin a chance to allocate a per-request context. */
271 krb5_preauth_request_context_init(krb5_context context)
274 struct krb5_preauth_context_module_st *mod;
276 if (context->preauth_context == NULL)
277 krb5_init_preauth_context(context);
278 if (context->preauth_context == NULL)
280 for (i = 0; i < context->preauth_context->n_modules; i++) {
281 mod = &context->preauth_context->modules[i];
282 if (mod->client_req_init != NULL)
283 mod->client_req_init(context, mod->moddata, mod->modreq_p);
287 /* Free the per-AS-REQ context. This means clearing any request-specific
288 * context which the plugin may have created. */
290 krb5_preauth_request_context_fini(krb5_context context)
293 struct krb5_preauth_context_module_st *mod;
295 if (context->preauth_context == NULL)
297 for (i = 0; i < context->preauth_context->n_modules; i++) {
298 mod = &context->preauth_context->modules[i];
299 if (mod->modreq != NULL) {
300 if (mod->client_req_fini != NULL)
301 mod->client_req_fini(context, mod->moddata, mod->modreq);
307 /* Add the named encryption type to the existing list of ktypes. */
309 grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
312 krb5_enctype *ktypes;
313 for (i = 0; i < *out_nktypes; i++) {
314 if ((*out_ktypes)[i] == ktype)
317 ktypes = malloc((*out_nktypes + 2) * sizeof(ktype));
319 for (i = 0; i < *out_nktypes; i++)
320 ktypes[i] = (*out_ktypes)[i];
324 *out_ktypes = ktypes;
330 * Add the given list of pa_data items to the existing list of items.
331 * Factored out here to make reading the do_preauth logic easier to read.
334 grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size,
335 krb5_pa_data **addition, int num_addition)
337 krb5_pa_data **pa_list;
340 if (out_pa_list == NULL || addition == NULL) {
344 if (*out_pa_list == NULL) {
345 /* Allocate room for the new additions and a NULL terminator. */
346 pa_list = malloc((num_addition + 1) * sizeof(krb5_pa_data *));
349 for (i = 0; i < num_addition; i++)
350 pa_list[i] = addition[i];
352 *out_pa_list = pa_list;
353 *out_pa_list_size = num_addition;
356 * Allocate room for the existing entries plus
357 * the new additions and a NULL terminator.
359 pa_list = malloc((*out_pa_list_size + num_addition + 1)
360 * sizeof(krb5_pa_data *));
363 for (i = 0; i < *out_pa_list_size; i++)
364 pa_list[i] = (*out_pa_list)[i];
365 for (j = 0; j < num_addition;)
366 pa_list[i++] = addition[j++];
369 *out_pa_list = pa_list;
370 *out_pa_list_size = i;
376 * Retrieve a specific piece of information required by the plugin and
377 * return it in a new krb5_data item. There are separate request_types
378 * to obtain the data and free it.
380 * This may require massaging data into a contrived format, but it will
381 * hopefully keep us from having to reveal library-internal functions
382 * or data to the plugin modules.
385 static krb5_error_code
386 client_data_proc(krb5_context kcontext, krb5_clpreauth_rock rock,
387 krb5_int32 request_type, krb5_data **retdata)
390 krb5_error_code retval;
393 if (rock->magic != CLIENT_ROCK_MAGIC)
398 switch (request_type) {
399 case krb5_clpreauth_get_etype:
402 ret = malloc(sizeof(krb5_data));
405 data = malloc(sizeof(krb5_enctype));
411 ret->length = sizeof(krb5_enctype);
412 eptr = (krb5_enctype *)data;
413 *eptr = *rock->etype;
418 case krb5_clpreauth_free_etype:
427 case krb5_clpreauth_fast_armor: {
428 krb5_keyblock *key = NULL;
429 ret = calloc(1, sizeof(krb5_data));
433 if (rock->fast_state->armor_key)
434 retval = krb5_copy_keyblock(kcontext, rock->fast_state->armor_key,
437 ret->data = (char *) key;
438 ret->length = key?sizeof(krb5_keyblock):0;
449 case krb5_clpreauth_free_fast_armor:
453 krb5_free_keyblock(kcontext, (krb5_keyblock *) ret->data);
463 /* Tweak the request body, for now adding any enctypes which the module claims
464 * to add support for to the list, but in the future perhaps doing more
465 * involved things. */
467 krb5_preauth_prepare_request(krb5_context kcontext,
468 krb5_gic_opt_ext *opte,
469 krb5_kdc_req *request)
473 if (kcontext->preauth_context == NULL) {
476 /* Add the module-specific enctype list to the request, but only if
477 * it's something we can safely modify. */
478 if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
479 for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
480 if (kcontext->preauth_context->modules[i].enctypes == NULL)
482 for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
483 grow_ktypes(&request->ktype, &request->nktypes,
484 kcontext->preauth_context->modules[i].enctypes[j]);
490 /* Find the first module which provides for the named preauth type which also
491 * hasn't had a chance to run yet (INFO modules don't count, because as a rule
492 * they don't generate preauth data), and run it. */
493 static krb5_error_code
494 run_preauth_plugins(krb5_context kcontext,
495 int module_required_flags,
496 krb5_kdc_req *request,
497 krb5_data *encoded_request_body,
498 krb5_data *encoded_previous_request,
499 krb5_pa_data *in_padata,
500 krb5_prompter_fct prompter,
502 krb5_clpreauth_get_as_key_fn gak_fct,
504 krb5_data *s2kparams,
506 krb5_clpreauth_rock preauth_rock,
507 krb5_keyblock *as_key,
508 krb5_pa_data ***out_pa_list,
509 int *out_pa_list_size,
512 krb5_gic_opt_ext *opte)
515 krb5_pa_data **out_pa_data;
517 struct krb5_preauth_context_module_st *module;
519 if (kcontext->preauth_context == NULL) {
522 /* iterate over all loaded modules */
523 for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
524 module = &kcontext->preauth_context->modules[i];
525 /* skip over those which don't match the preauth type */
526 if (module->pa_type != in_padata->pa_type)
528 /* skip over those which don't match the flags (INFO vs REAL, mainly) */
529 if ((module->flags & module_required_flags) == 0)
531 /* if it's a REAL module, try to call it only once per library call */
532 if (module_required_flags & PA_REAL) {
533 if (module->use_count > 0) {
534 TRACE_PREAUTH_SKIP(kcontext, module->name, module->pa_type);
539 /* run the module's callback function */
542 fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
543 module->name, module->pa_type, module->flags);
545 ret = module->client_process(kcontext, module->moddata,
547 (krb5_get_init_creds_opt *)opte,
548 client_data_proc, preauth_rock,
549 request, encoded_request_body,
550 encoded_previous_request, in_padata,
551 prompter, prompter_data, gak_fct,
552 gak_data, salt, s2kparams, as_key,
554 TRACE_PREAUTH_PROCESS(kcontext, module->name, module->pa_type,
556 /* Make note of the module's flags and status. */
557 *module_flags = module->flags;
559 /* Save the new preauth data item. */
560 if (out_pa_data != NULL) {
562 for (j = 0; out_pa_data[j] != NULL; j++);
563 ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
570 if (i >= kcontext->preauth_context->n_modules) {
576 static inline krb5_data
577 padata2data(krb5_pa_data p)
582 d.data = (char *) p.contents;
586 static krb5_error_code
587 pa_salt(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
588 krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams,
589 krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter,
590 void *prompter_data, krb5_gic_get_as_key_fct gak_fct, void *gak_data)
593 krb5_error_code retval;
595 tmp = padata2data(*in_padata);
596 krb5_free_data_contents(context, salt);
597 retval = krb5int_copy_data_contents(context, &tmp, salt);
601 TRACE_PREAUTH_SALT(context, salt, in_padata->pa_type);
602 if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
603 salt->length = SALT_TYPE_AFS_LENGTH;
608 static krb5_error_code
609 pa_fx_cookie(krb5_context context, krb5_kdc_req *request,
610 krb5_pa_data *in_padata, krb5_pa_data **out_padata,
611 krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype,
612 krb5_keyblock *as_key, krb5_prompter_fct prompter,
613 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
616 krb5_pa_data *pa = calloc(1, sizeof(krb5_pa_data));
617 krb5_octet *contents;
619 TRACE_PREAUTH_COOKIE(context, in_padata->length, in_padata->contents);
622 contents = malloc(in_padata->length);
623 if (contents == NULL) {
628 pa->contents = contents;
629 memcpy(contents, in_padata->contents, pa->length);
634 static krb5_error_code
635 pa_enc_timestamp(krb5_context context, krb5_kdc_req *request,
636 krb5_pa_data *in_padata, krb5_pa_data **out_padata,
637 krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype,
638 krb5_keyblock *as_key, krb5_prompter_fct prompter,
639 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
643 krb5_pa_enc_ts pa_enc;
645 krb5_enc_data enc_data;
648 if (as_key->length == 0) {
650 fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
652 if ((int) salt->length > 0)
653 fprintf (stderr, " '%.*s'", salt->length, salt->data);
654 fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
655 *etype, request->ktype[0]);
657 if ((ret = ((*gak_fct)(context, request->client,
658 *etype ? *etype : request->ktype[0],
659 prompter, prompter_data,
660 salt, s2kparams, as_key, gak_data))))
662 TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key);
665 /* now get the time of day, and encrypt it accordingly */
667 if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
670 if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
673 ret = krb5_encrypt_helper(context, as_key,
674 KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
676 TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec,
677 tmp, &enc_data.ciphertext);
679 krb5_free_data(context, tmp);
684 ret = encode_krb5_enc_data(&enc_data, &tmp);
686 free(enc_data.ciphertext.data);
691 if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
692 krb5_free_data(context, tmp);
696 pa->magic = KV5M_PA_DATA;
697 pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
698 pa->length = tmp->length;
699 pa->contents = (krb5_octet *) tmp->data;
710 * PKINIT. One function to generate AS-REQ, one to parse AS-REP
712 #define PKINIT_DEBUG 0
714 #define kdcPkinitDebug(args...) printf(args)
716 #define kdcPkinitDebug(args...)
719 static krb5_error_code
720 pa_pkinit_gen_req(krb5_context context,
721 krb5_kdc_req *request,
722 krb5_pa_data *in_padata,
723 krb5_pa_data **out_padata,
725 krb5_data *s2kparams,
727 krb5_keyblock *as_key,
728 krb5_prompter_fct prompter,
730 krb5_gic_get_as_key_fct gak_fct,
733 krb5_error_code krtn;
734 krb5_data out_data = {0, 0, NULL};
735 krb5_timestamp kctime = 0;
736 krb5_int32 cusec = 0;
739 krb5_pkinit_signing_cert_t client_cert;
740 krb5_data *der_req = NULL;
741 char *client_principal = NULL;
742 char *server_principal = NULL;
743 unsigned char nonce_bytes[4];
744 krb5_data nonce_data = {0, 4, (char *)nonce_bytes};
748 * Trusted CA list and specific KC cert optionally obtained via
749 * krb5_pkinit_get_server_certs(). All are DER-encoded certs.
751 krb5_data *trusted_CAs = NULL;
752 krb5_ui_4 num_trusted_CAs;
753 krb5_data kdc_cert = {0};
755 kdcPkinitDebug("pa_pkinit_gen_req\n");
757 /* If we don't have a client cert, we're done */
758 if(request->client == NULL) {
759 kdcPkinitDebug("No request->client; aborting PKINIT\n");
760 return KRB5KDC_ERR_PREAUTH_FAILED;
762 krtn = krb5_unparse_name(context, request->client, &client_principal);
766 krtn = krb5_pkinit_get_client_cert(client_principal, &client_cert);
767 free(client_principal);
769 kdcPkinitDebug("No client cert; aborting PKINIT\n");
773 /* optional platform-dependent CA list and KDC cert */
774 krtn = krb5_unparse_name(context, request->server, &server_principal);
778 krtn = krb5_pkinit_get_server_certs(client_principal, server_principal,
779 &trusted_CAs, &num_trusted_CAs, &kdc_cert);
784 /* checksum of the encoded KDC-REQ-BODY */
785 krtn = encode_krb5_kdc_req_body(request, &der_req);
787 kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
790 krtn = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0, der_req, &cksum);
795 krtn = krb5_us_timeofday(context, &kctime, &cusec);
800 /* cook up a random 4-byte nonce */
801 krtn = krb5_c_random_make_octets(context, &nonce_data);
805 for(dex=0; dex<4; dex++) {
807 nonce |= nonce_bytes[dex];
810 krtn = krb5int_pkinit_as_req_create(context,
811 kctime, cusec, nonce, &cksum,
813 trusted_CAs, num_trusted_CAs,
814 (kdc_cert.data ? &kdc_cert : NULL),
817 kdcPkinitDebug("error %d on pkinit_as_req_create; aborting PKINIT\n", (int)krtn);
820 *out_padata = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
821 if(*out_padata == NULL) {
826 (*out_padata)->magic = KV5M_PA_DATA;
827 (*out_padata)->pa_type = KRB5_PADATA_PK_AS_REQ;
828 (*out_padata)->length = out_data.length;
829 (*out_padata)->contents = (krb5_octet *)out_data.data;
833 krb5_pkinit_release_cert(client_cert);
836 free(cksum.contents);
839 krb5_free_data(context, der_req);
841 if(server_principal) {
842 free(server_principal);
844 /* free data mallocd by krb5_pkinit_get_server_certs() */
847 for(udex=0; udex<num_trusted_CAs; udex++) {
848 free(trusted_CAs[udex].data);
859 /* If and only if the realm is that of a Local KDC, accept
860 * the KDC certificate as valid if its hash matches the
864 local_kdc_cert_match(krb5_context context,
865 krb5_data *signer_cert,
866 krb5_principal client)
868 static const char lkdcprefix[] = "LKDC:SHA1.";
869 krb5_boolean match = FALSE;
870 size_t cert_hash_len;
872 const char *realm_hash;
873 size_t realm_hash_len;
875 if (client->realm.length <= sizeof(lkdcprefix) ||
876 0 != memcmp(lkdcprefix, client->realm.data, sizeof(lkdcprefix)-1))
878 realm_hash = &client->realm.data[sizeof(lkdcprefix)-1];
879 realm_hash_len = client->realm.length - sizeof(lkdcprefix) + 1;
880 kdcPkinitDebug("checking realm versus certificate hash\n");
881 if (NULL != (cert_hash = krb5_pkinit_cert_hash_str(signer_cert))) {
882 kdcPkinitDebug("hash = %s\n", cert_hash);
883 cert_hash_len = strlen(cert_hash);
884 if (cert_hash_len == realm_hash_len &&
885 0 == memcmp(cert_hash, realm_hash, cert_hash_len))
889 kdcPkinitDebug("result: %s\n", match ? "matches" : "does not match");
893 static krb5_error_code
894 pa_pkinit_parse_rep(krb5_context context,
895 krb5_kdc_req *request,
896 krb5_pa_data *in_padata,
897 krb5_pa_data **out_padata,
899 krb5_data *s2kparams,
901 krb5_keyblock *as_key,
902 krb5_prompter_fct prompter,
904 krb5_gic_get_as_key_fct gak_fct,
907 krb5int_cert_sig_status sig_status = (krb5int_cert_sig_status)-999;
908 krb5_error_code krtn;
910 krb5_keyblock local_key = {0};
911 krb5_pkinit_signing_cert_t client_cert;
912 char *princ_name = NULL;
913 krb5_checksum as_req_checksum_rcd = {0}; /* received checksum */
914 krb5_checksum as_req_checksum_gen = {0}; /* calculated checksum */
915 krb5_data *encoded_as_req = NULL;
916 krb5_data signer_cert = {0};
919 kdcPkinitDebug("pa_pkinit_parse_rep\n");
920 if((in_padata == NULL) || (in_padata->length== 0)) {
921 kdcPkinitDebug("pa_pkinit_parse_rep: no in_padata\n");
922 return KRB5KDC_ERR_PREAUTH_FAILED;
925 /* If we don't have a client cert, we're done */
926 if(request->client == NULL) {
927 kdcPkinitDebug("No request->client; aborting PKINIT\n");
928 return KRB5KDC_ERR_PREAUTH_FAILED;
930 krtn = krb5_unparse_name(context, request->client, &princ_name);
934 krtn = krb5_pkinit_get_client_cert(princ_name, &client_cert);
937 kdcPkinitDebug("No client cert; aborting PKINIT\n");
941 memset(&local_key, 0, sizeof(local_key));
942 asRep.data = (char *)in_padata->contents;
943 asRep.length = in_padata->length;
944 krtn = krb5int_pkinit_as_rep_parse(context, &asRep, client_cert,
945 &local_key, &as_req_checksum_rcd, &sig_status,
946 &signer_cert, NULL, NULL);
948 kdcPkinitDebug("pkinit_as_rep_parse returned %d\n", (int)krtn);
954 case pki_cs_unknown_root:
955 if (local_kdc_cert_match(context, &signer_cert, request->client))
959 kdcPkinitDebug("pa_pkinit_parse_rep: bad cert/sig status %d\n",
961 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
965 /* calculate checksum of incoming AS-REQ using the decryption key
966 * we just got from the ReplyKeyPack */
967 krtn = encode_krb5_as_req(request, &encoded_as_req);
971 krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
972 &local_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
973 encoded_as_req, &as_req_checksum_gen);
977 if((as_req_checksum_gen.length != as_req_checksum_rcd.length) ||
978 memcmp(as_req_checksum_gen.contents,
979 as_req_checksum_rcd.contents,
980 as_req_checksum_gen.length)) {
981 kdcPkinitDebug("pa_pkinit_parse_rep: checksum miscompare\n");
982 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
986 /* We have the key; transfer to caller */
987 if (as_key->length) {
988 krb5_free_keyblock_contents(context, as_key);
993 fprintf(stderr, "pa_pkinit_parse_rep: SUCCESS\n");
994 fprintf(stderr, "enctype %d keylen %d keydata %02x %02x %02x %02x...\n",
995 (int)as_key->enctype, (int)as_key->length,
996 as_key->contents[0], as_key->contents[1],
997 as_key->contents[2], as_key->contents[3]);
1003 if (signer_cert.data) {
1004 free(signer_cert.data);
1006 if(as_req_checksum_rcd.contents) {
1007 free(as_req_checksum_rcd.contents);
1009 if(as_req_checksum_gen.contents) {
1010 free(as_req_checksum_gen.contents);
1012 if(encoded_as_req) {
1013 krb5_free_data(context, encoded_as_req);
1015 if(krtn && (local_key.contents != NULL)) {
1016 krb5_free_keyblock_contents(context, &local_key);
1020 #endif /* APPLE_PKINIT */
1022 /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
1024 #define SAMDATA(kdata, str, maxsize) \
1025 (int)((kdata.length)? \
1026 ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
1029 ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
1031 sam_challenge_banner(krb5_int32 sam_type)
1036 case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
1037 label = _("Challenge for Enigma Logic mechanism");
1039 case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */
1040 case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */
1041 label = _("Challenge for Digital Pathways mechanism");
1043 case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */
1044 case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */
1045 label = _("Challenge for Activcard mechanism");
1047 case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */
1048 label = _("Challenge for Enhanced S/Key mechanism");
1050 case PA_SAM_TYPE_SKEY: /* Traditional S/Key */
1051 label = _("Challenge for Traditional S/Key mechanism");
1053 case PA_SAM_TYPE_SECURID: /* Security Dynamics */
1054 label = _("Challenge for Security Dynamics mechanism");
1056 case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */
1057 label = _("Challenge for Security Dynamics mechanism");
1060 label = _("Challenge from authentication server");
1067 static krb5_error_code
1068 pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
1069 krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams,
1070 krb5_enctype *etype, krb5_keyblock *as_key,
1071 krb5_prompter_fct prompter, void *prompter_data,
1072 krb5_gic_get_as_key_fct gak_fct, void *gak_data)
1074 krb5_error_code retval;
1075 krb5_sam_challenge_2 *sc2 = NULL;
1076 krb5_sam_challenge_2_body *sc2b = NULL;
1078 krb5_data response_data;
1079 char name[100], banner[100], prompt[100], response[100];
1080 krb5_prompt kprompt;
1081 krb5_prompt_type prompt_type;
1083 krb5_checksum **cksum;
1084 krb5_data *scratch = NULL;
1085 krb5_boolean valid_cksum = 0;
1086 krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
1087 krb5_sam_response_2 sr2;
1089 krb5_pa_data *sam_padata;
1091 if (prompter == NULL)
1092 return KRB5_LIBOS_CANTREADPWD;
1094 tmp_data.length = in_padata->length;
1095 tmp_data.data = (char *)in_padata->contents;
1097 if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
1100 retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
1103 krb5_free_sam_challenge_2(context, sc2);
1107 if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
1108 krb5_free_sam_challenge_2(context, sc2);
1109 krb5_free_sam_challenge_2_body(context, sc2b);
1110 return(KRB5_SAM_NO_CHECKSUM);
1113 if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
1114 krb5_free_sam_challenge_2(context, sc2);
1115 krb5_free_sam_challenge_2_body(context, sc2b);
1116 return(KRB5_SAM_UNSUPPORTED);
1119 if (!krb5_c_valid_enctype(sc2b->sam_etype)) {
1120 krb5_free_sam_challenge_2(context, sc2);
1121 krb5_free_sam_challenge_2_body(context, sc2b);
1122 return(KRB5_SAM_INVALID_ETYPE);
1125 /* All of the above error checks are KDC-specific, that is, they */
1126 /* assume a failure in the KDC reply. By returning anything other */
1127 /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
1128 /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
1129 /* most likely go on to try the AS_REQ against master KDC */
1131 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1132 /* We will need the password to obtain the key used for */
1133 /* the checksum, and encryption of the sam_response. */
1134 /* Go ahead and get it now, preserving the ordering of */
1135 /* prompts for the user. */
1137 retval = (gak_fct)(context, request->client,
1138 sc2b->sam_etype, prompter,
1139 prompter_data, salt, s2kparams, as_key, gak_data);
1141 krb5_free_sam_challenge_2(context, sc2);
1142 krb5_free_sam_challenge_2_body(context, sc2b);
1147 snprintf(name, sizeof(name), "%.*s",
1148 SAMDATA(sc2b->sam_type_name, _("SAM Authentication"),
1151 snprintf(banner, sizeof(banner), "%.*s",
1152 SAMDATA(sc2b->sam_challenge_label,
1153 sam_challenge_banner(sc2b->sam_type),
1156 snprintf(prompt, sizeof(prompt), "%s%.*s%s%.*s",
1157 sc2b->sam_challenge.length?"Challenge is [":"",
1158 SAMDATA(sc2b->sam_challenge, "", 20),
1159 sc2b->sam_challenge.length?"], ":"",
1160 SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
1162 response_data.data = response;
1163 response_data.length = sizeof(response);
1164 kprompt.prompt = prompt;
1166 kprompt.reply = &response_data;
1168 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
1169 krb5int_set_prompt_types(context, &prompt_type);
1171 if ((retval = ((*prompter)(context, prompter_data, name,
1172 banner, 1, &kprompt)))) {
1173 krb5_free_sam_challenge_2(context, sc2);
1174 krb5_free_sam_challenge_2_body(context, sc2b);
1175 krb5int_set_prompt_types(context, 0);
1179 krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
1181 /* Generate salt used by string_to_key() */
1182 if (((int) salt->length == -1) && (salt->data == NULL)) {
1184 krb5_principal2salt(context, request->client, &defsalt))) {
1185 krb5_free_sam_challenge_2(context, sc2);
1186 krb5_free_sam_challenge_2_body(context, sc2b);
1194 /* Get encryption key to be used for checksum and sam_response */
1195 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1196 /* as_key = string_to_key(password) */
1198 if (as_key->length) {
1199 krb5_free_keyblock_contents(context, as_key);
1203 /* generate a key using the supplied password */
1204 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1205 (krb5_data *)gak_data, salt, as_key);
1208 krb5_free_sam_challenge_2(context, sc2);
1209 krb5_free_sam_challenge_2_body(context, sc2b);
1210 if (defsalt.length) free(defsalt.data);
1214 if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
1215 /* as_key = combine_key (as_key, string_to_key(SAD)) */
1216 krb5_keyblock tmp_kb;
1218 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1219 &response_data, salt, &tmp_kb);
1222 krb5_free_sam_challenge_2(context, sc2);
1223 krb5_free_sam_challenge_2_body(context, sc2b);
1224 if (defsalt.length) free(defsalt.data);
1228 /* This should be a call to the crypto library some day */
1229 /* key types should already match the sam_etype */
1230 retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
1233 krb5_free_sam_challenge_2(context, sc2);
1234 krb5_free_sam_challenge_2_body(context, sc2b);
1235 if (defsalt.length) free(defsalt.data);
1238 krb5_free_keyblock_contents(context, &tmp_kb);
1245 /* as_key = string_to_key(SAD) */
1247 if (as_key->length) {
1248 krb5_free_keyblock_contents(context, as_key);
1252 /* generate a key using the supplied password */
1253 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1254 &response_data, salt, as_key);
1260 krb5_free_sam_challenge_2(context, sc2);
1261 krb5_free_sam_challenge_2_body(context, sc2b);
1266 /* Now we have a key, verify the checksum on the sam_challenge */
1268 cksum = sc2->sam_cksum;
1270 for (; *cksum; cksum++) {
1271 if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type))
1273 /* Check this cksum */
1274 retval = krb5_c_verify_checksum(context, as_key,
1275 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
1276 &sc2->sam_challenge_2_body,
1277 *cksum, &valid_cksum);
1279 krb5_free_data(context, scratch);
1280 krb5_free_sam_challenge_2(context, sc2);
1281 krb5_free_sam_challenge_2_body(context, sc2b);
1289 krb5_free_sam_challenge_2(context, sc2);
1290 krb5_free_sam_challenge_2_body(context, sc2b);
1292 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
1293 * can interpret that as "password incorrect", which is probably
1294 * the best error we can return in this situation.
1296 return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
1299 /* fill in enc_sam_response_enc_2 */
1300 enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
1301 enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
1302 if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
1303 enc_sam_response_enc_2.sam_sad = response_data;
1305 enc_sam_response_enc_2.sam_sad.data = NULL;
1306 enc_sam_response_enc_2.sam_sad.length = 0;
1309 /* encode and encrypt enc_sam_response_enc_2 with as_key */
1310 retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
1313 krb5_free_sam_challenge_2(context, sc2);
1314 krb5_free_sam_challenge_2_body(context, sc2b);
1318 /* Fill in sam_response_2 */
1319 memset(&sr2, 0, sizeof(sr2));
1320 sr2.sam_type = sc2b->sam_type;
1321 sr2.sam_flags = sc2b->sam_flags;
1322 sr2.sam_track_id = sc2b->sam_track_id;
1323 sr2.sam_nonce = sc2b->sam_nonce;
1325 /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
1326 /* enc_sam_response_enc_2 from above */
1328 retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
1331 krb5_free_sam_challenge_2(context, sc2);
1332 krb5_free_sam_challenge_2_body(context, sc2b);
1333 krb5_free_data(context, scratch);
1336 sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;
1338 sr2.sam_enc_nonce_or_sad.ciphertext.data =
1339 (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
1341 if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
1342 krb5_free_sam_challenge_2(context, sc2);
1343 krb5_free_sam_challenge_2_body(context, sc2b);
1344 krb5_free_data(context, scratch);
1348 retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
1349 NULL, scratch, &sr2.sam_enc_nonce_or_sad);
1351 krb5_free_sam_challenge_2(context, sc2);
1352 krb5_free_sam_challenge_2_body(context, sc2b);
1353 krb5_free_data(context, scratch);
1354 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
1357 krb5_free_data(context, scratch);
1360 /* Encode the sam_response_2 */
1361 retval = encode_krb5_sam_response_2(&sr2, &scratch);
1362 krb5_free_sam_challenge_2(context, sc2);
1363 krb5_free_sam_challenge_2_body(context, sc2b);
1364 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
1370 /* Almost there, just need to make padata ! */
1371 sam_padata = malloc(sizeof(krb5_pa_data));
1372 if (sam_padata == NULL) {
1373 krb5_free_data(context, scratch);
1377 sam_padata->magic = KV5M_PA_DATA;
1378 sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
1379 sam_padata->length = scratch->length;
1380 sam_padata->contents = (krb5_octet *) scratch->data;
1383 *out_padata = sam_padata;
1388 static krb5_error_code
1389 pa_s4u_x509_user(krb5_context context, krb5_kdc_req *request,
1390 krb5_pa_data *in_padata, krb5_pa_data **out_padata,
1391 krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype,
1392 krb5_keyblock *as_key, krb5_prompter_fct prompter,
1393 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
1396 krb5_s4u_userid *userid = (krb5_s4u_userid *)gak_data; /* XXX private contract */
1397 krb5_pa_data *s4u_padata;
1398 krb5_error_code code;
1399 krb5_principal client;
1406 code = krb5_copy_principal(context, request->client, &client);
1410 if (userid->user != NULL)
1411 krb5_free_principal(context, userid->user);
1412 userid->user = client;
1414 if (userid->subject_cert.length != 0) {
1415 s4u_padata = malloc(sizeof(*s4u_padata));
1416 if (s4u_padata == NULL)
1419 s4u_padata->magic = KV5M_PA_DATA;
1420 s4u_padata->pa_type = KRB5_PADATA_S4U_X509_USER;
1421 s4u_padata->contents = malloc(userid->subject_cert.length);
1422 if (s4u_padata->contents == NULL) {
1426 memcpy(s4u_padata->contents, userid->subject_cert.data, userid->subject_cert.length);
1427 s4u_padata->length = userid->subject_cert.length;
1429 *out_padata = s4u_padata;
1435 /* FIXME - order significant? */
1436 static const pa_types_t pa_types[] = {
1438 KRB5_PADATA_PW_SALT,
1443 KRB5_PADATA_AFS3_SALT,
1449 KRB5_PADATA_PK_AS_REQ,
1454 KRB5_PADATA_PK_AS_REP,
1455 pa_pkinit_parse_rep,
1458 #endif /* APPLE_PKINIT */
1460 KRB5_PADATA_ENC_TIMESTAMP,
1465 KRB5_PADATA_SAM_CHALLENGE_2,
1470 KRB5_PADATA_FX_COOKIE,
1475 KRB5_PADATA_S4U_X509_USER,
1487 * If one of the modules can adjust its AS_REQ data using the contents of the
1488 * err_reply, return 0. If it's the sort of correction which requires that we
1489 * ask the user another question, we let the calling application deal with it.
1491 krb5_error_code KRB5_CALLCONV
1492 krb5_do_preauth_tryagain(krb5_context kcontext,
1493 krb5_kdc_req *request,
1494 krb5_data *encoded_request_body,
1495 krb5_data *encoded_previous_request,
1496 krb5_pa_data **padata,
1497 krb5_pa_data ***return_padata,
1498 krb5_error *err_reply,
1499 krb5_data *salt, krb5_data *s2kparams,
1500 krb5_enctype *etype,
1501 krb5_keyblock *as_key,
1502 krb5_prompter_fct prompter, void *prompter_data,
1503 krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1504 krb5_clpreauth_rock preauth_rock,
1505 krb5_gic_opt_ext *opte)
1507 krb5_error_code ret;
1508 krb5_pa_data **out_padata;
1509 krb5_preauth_context *context;
1510 struct krb5_preauth_context_module_st *module;
1512 int out_pa_list_size = 0;
1514 ret = KRB5KRB_ERR_GENERIC;
1515 if (kcontext->preauth_context == NULL) {
1516 return KRB5KRB_ERR_GENERIC;
1518 context = kcontext->preauth_context;
1519 if (context == NULL) {
1520 return KRB5KRB_ERR_GENERIC;
1523 TRACE_PREAUTH_TRYAGAIN_INPUT(kcontext, padata);
1525 for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
1527 for (j = 0; j < context->n_modules; j++) {
1528 module = &context->modules[j];
1529 if (module->pa_type != padata[i]->pa_type) {
1532 if (module->client_tryagain == NULL) {
1535 if ((*module->client_tryagain)(kcontext, module->moddata,
1537 (krb5_get_init_creds_opt *)opte,
1541 encoded_request_body,
1542 encoded_previous_request,
1545 prompter, prompter_data,
1546 gak_fct, gak_data, salt, s2kparams,
1548 &out_padata) == 0) {
1549 if (out_padata != NULL) {
1551 for (k = 0; out_padata[k] != NULL; k++);
1552 grow_pa_list(return_padata, &out_pa_list_size,
1555 TRACE_PREAUTH_TRYAGAIN_OUTPUT(kcontext, *return_padata);
1564 krb5_error_code KRB5_CALLCONV
1565 krb5_do_preauth(krb5_context context,
1566 krb5_kdc_req *request,
1567 krb5_data *encoded_request_body,
1568 krb5_data *encoded_previous_request,
1569 krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
1570 krb5_data *salt, krb5_data *s2kparams,
1571 krb5_enctype *etype,
1572 krb5_keyblock *as_key,
1573 krb5_prompter_fct prompter, void *prompter_data,
1574 krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1575 krb5_clpreauth_rock preauth_rock, krb5_gic_opt_ext *opte)
1578 int i, j, out_pa_list_size;
1579 int seen_etype_info2 = 0;
1580 krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
1582 krb5_etype_info etype_info = NULL;
1583 krb5_error_code ret;
1584 static const int paorder[] = { PA_INFO, PA_REAL };
1587 if (in_padata == NULL) {
1592 TRACE_PREAUTH_INPUT(context, in_padata);
1595 out_pa_list_size = 0;
1597 /* first do all the informational preauths, then the first real one */
1599 for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
1601 for (i=0; in_padata[i] && !realdone; i++) {
1602 int k, l, etype_found, valid_etype_found;
1604 * This is really gross, but is necessary to prevent
1605 * lossage when talking to a 1.0.x KDC, which returns an
1606 * erroneous PA-PW-SALT when it returns a KRB-ERROR
1607 * requiring additional preauth.
1609 switch (in_padata[i]->pa_type) {
1610 case KRB5_PADATA_ETYPE_INFO:
1611 case KRB5_PADATA_ETYPE_INFO2:
1613 krb5_preauthtype pa_type = in_padata[i]->pa_type;
1615 if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
1617 if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1618 krb5_free_etype_info( context, etype_info);
1623 scratch.length = in_padata[i]->length;
1624 scratch.data = (char *) in_padata[i]->contents;
1625 if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1627 ret = decode_krb5_etype_info2(&scratch, &etype_info);
1629 else ret = decode_krb5_etype_info(&scratch, &etype_info);
1631 ret = 0; /*Ignore error and etype_info element*/
1633 krb5_free_etype_info( context, etype_info);
1637 if (etype_info[0] == NULL) {
1638 krb5_free_etype_info(context, etype_info);
1643 * Select first etype in our request which is also in
1644 * etype-info (preferring client request ktype order).
1646 for (etype_found = 0, valid_etype_found = 0, k = 0;
1647 !etype_found && k < request->nktypes; k++) {
1648 for (l = 0; etype_info[l]; l++) {
1649 if (etype_info[l]->etype == request->ktype[k]) {
1653 /* check if program has support for this etype for more
1654 * precise error reporting.
1656 if (krb5_c_valid_enctype(etype_info[l]->etype))
1657 valid_etype_found++;
1661 if (valid_etype_found) {
1662 /* supported enctype but not requested */
1663 ret = KRB5_CONFIG_ETYPE_NOSUPP;
1667 /* unsupported enctype */
1668 ret = KRB5_PROG_ETYPE_NOSUPP;
1673 scratch.data = (char *) etype_info[l]->salt;
1674 scratch.length = etype_info[l]->length;
1675 krb5_free_data_contents(context, salt);
1676 if (scratch.length == KRB5_ETYPE_NO_SALT)
1679 if ((ret = krb5int_copy_data_contents( context, &scratch, salt)) != 0)
1681 *etype = etype_info[l]->etype;
1682 krb5_free_data_contents(context, s2kparams);
1683 if ((ret = krb5int_copy_data_contents(context,
1684 &etype_info[l]->s2kparams,
1687 TRACE_PREAUTH_ETYPE_INFO(context, *etype, salt, s2kparams);
1690 case KRB5_PADATA_PW_SALT:
1691 case KRB5_PADATA_AFS3_SALT:
1698 /* Try the internally-provided preauth type list. */
1699 if (!realdone) for (j=0; pa_types[j].type >= 0; j++) {
1700 if ((in_padata[i]->pa_type == pa_types[j].type) &&
1701 (pa_types[j].flags & paorder[h])) {
1703 fprintf (stderr, "calling internal function for pa_type "
1704 "%d, flag %d\n", pa_types[j].type, paorder[h]);
1708 if ((ret = ((*pa_types[j].fct)(context, request,
1709 in_padata[i], &out_pa,
1710 salt, s2kparams, etype, as_key,
1711 prompter, prompter_data,
1712 gak_fct, gak_data)))) {
1713 if (paorder[h] == PA_INFO) {
1714 TRACE_PREAUTH_INFO_FAIL(context,
1715 in_padata[i]->pa_type,
1718 continue; /* PA_INFO type failed, ignore */
1724 ret = grow_pa_list(&out_pa_list, &out_pa_list_size,
1729 if (paorder[h] == PA_REAL)
1734 /* Try to use plugins now. */
1736 krb5_init_preauth_context(context);
1737 if (context->preauth_context != NULL) {
1738 int module_ret = 0, module_flags;
1740 fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
1741 in_padata[i]->pa_type, paorder[h]);
1743 ret = run_preauth_plugins(context,
1746 encoded_request_body,
1747 encoded_previous_request,
1762 if (module_ret == 0) {
1763 if (paorder[h] == PA_REAL) {
1773 TRACE_PREAUTH_OUTPUT(context, out_pa_list);
1774 *out_padata = out_pa_list;
1776 krb5_free_etype_info(context, etype_info);
1781 out_pa_list[out_pa_list_size++] = NULL;
1782 krb5_free_pa_data(context, out_pa_list);
1785 krb5_free_etype_info(context, etype_info);
1790 * Give all the preauth plugins a look at the preauth option which
1794 krb5_preauth_supply_preauth_data(krb5_context context, krb5_gic_opt_ext *opte,
1795 const char *attr, const char *value)
1797 krb5_error_code retval = 0;
1799 struct krb5_preauth_context_module_st *mod;
1800 const char *emsg = NULL;
1802 if (context->preauth_context == NULL)
1803 krb5_init_preauth_context(context);
1804 if (context->preauth_context == NULL) {
1806 krb5_set_error_message(context, retval,
1807 _("Unable to initialize preauth context"));
1812 * Go down the list of preauth modules, and supply them with the
1813 * attribute/value pair.
1815 for (i = 0; i < context->preauth_context->n_modules; i++) {
1816 mod = &context->preauth_context->modules[i];
1817 if (mod->client_supply_gic_opts == NULL)
1819 retval = mod->client_supply_gic_opts(context, mod->moddata,
1820 (krb5_get_init_creds_opt *)opte,
1823 emsg = krb5_get_error_message(context, retval);
1824 krb5_set_error_message(context, retval, _("Preauth plugin %s: %s"),
1826 krb5_free_error_message(context, emsg);