aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Coffman <kwc@citi.umich.edu>2006-12-12 03:08:07 +0000
committerKevin Coffman <kwc@citi.umich.edu>2006-12-12 03:08:07 +0000
commit34731fd9dd830ebdc3c3e3ce270b826bd8bbd350 (patch)
tree06e9792934a6ae3ff25ce5d8cc17f041a65ae0a4
parent9767459e6b9f4937b3ad2dd06affac3c8d7f4375 (diff)
downloadkrb5-34731fd9dd830ebdc3c3e3ce270b826bd8bbd350.zip
krb5-34731fd9dd830ebdc3c3e3ce270b826bd8bbd350.tar.gz
krb5-34731fd9dd830ebdc3c3e3ce270b826bd8bbd350.tar.bz2
Pull in changes for the extended get_init_creds_opt structure
Pull in changes to add get_init_creds_opt_set_pa(), get_init_creds_opt_get_pa(), and get_init_creds_opt_free_pa() Change client interface to pass in the get_init_creds_opt structure to the process and tryagain functions. Pull in changes to kinit to pass preauth options entered with "-X" Create typedefs for all the preauth plugin client and server interface functions and use them. Eliminates mismatches and enables better type checking of the interface paremeters. Add *temporary* code to client side of pkinit to handle preauth options and set the appropriate environment variables. (Currently only X509_user_identity, X509_anchors, and flag_RSA_PROTOCOL are handled.) Add code to use krb5int_accessor to obtain pointers to internal functions for ASN.1 encode/decode routines rather than exporting them from libkrb5. Various updates and improvements in the pkinit smartcard code. git-svn-id: svn://anonsvn.mit.edu/krb5/users/coffman/pkinit@18937 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/clients/kinit/kinit.c108
-rw-r--r--src/clients/kpasswd/kpasswd.c22
-rw-r--r--src/clients/kpasswd/ksetpwd.c23
-rw-r--r--src/include/k5-int-pkinit.h6
-rw-r--r--src/include/k5-int.h186
-rw-r--r--src/include/krb5/krb5.hin30
-rw-r--r--src/include/krb5/preauth_plugin.h403
-rw-r--r--src/kdc/kdc_preauth.c58
-rw-r--r--src/lib/krb5/asn.1/asn1_k_decode.c10
-rw-r--r--src/lib/krb5/asn.1/asn1_k_encode.c1
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c8
-rw-r--r--src/lib/krb5/krb/gic_keytab.c34
-rw-r--r--src/lib/krb5/krb/gic_opt.c417
-rw-r--r--src/lib/krb5/krb/gic_pwd.c77
-rw-r--r--src/lib/krb5/krb/preauth2.c68
-rw-r--r--src/lib/krb5/libkrb5.exports30
-rw-r--r--src/lib/krb5/os/accessor.c24
-rw-r--r--src/lib/krb5_32.def5
-rw-r--r--src/plugins/preauth/cksum_body/cksum_body_main.c90
-rw-r--r--src/plugins/preauth/pkinit/Makefile.in2
-rw-r--r--src/plugins/preauth/pkinit/pkinit.h46
-rw-r--r--src/plugins/preauth/pkinit/pkinit_accessor.c100
-rw-r--r--src/plugins/preauth/pkinit/pkinit_accessor.h67
-rw-r--r--src/plugins/preauth/pkinit/pkinit_clnt.c723
-rw-r--r--src/plugins/preauth/pkinit/pkinit_lib.c218
-rw-r--r--src/plugins/preauth/pkinit/pkinit_srv.c144
-rw-r--r--src/plugins/preauth/wpse/wpse_main.c17
27 files changed, 2301 insertions, 616 deletions
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 452d98c..f8e5b77 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -38,6 +38,7 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
+#include <errno.h>
#include <com_err.h>
#ifdef GETOPT_LONG
@@ -143,6 +144,9 @@ struct k_opts
char* k4_cache_name;
action_type action;
+
+ int num_pa_opts;
+ krb5_gic_opt_pa_data *pa_opts;
};
struct k5_data
@@ -283,6 +287,37 @@ static void extended_com_err_fn (const char *myprog, errcode_t code,
fprintf (stderr, "\n");
}
+static int
+add_preauth_opt(struct k_opts *opts, char *av)
+{
+ char *sep, *v;
+ krb5_gic_opt_pa_data *p, *x;
+
+ if (opts->num_pa_opts == 0) {
+ opts->pa_opts = malloc(sizeof(krb5_gic_opt_pa_data));
+ if (opts->pa_opts == NULL)
+ return ENOMEM;
+ } else {
+ size_t newsize = (opts->num_pa_opts + 1) * sizeof(krb5_gic_opt_pa_data);
+ x = realloc(opts->pa_opts, newsize);
+ if (x == NULL)
+ return ENOMEM;
+ opts->pa_opts = x;
+ }
+ p = &opts->pa_opts[opts->num_pa_opts];
+ sep = strchr(av, '=');
+ if (sep) {
+ *sep = '\0';
+ v = ++sep;
+ p->value = v;
+ } else {
+ p->value = "yes";
+ }
+ p->attr = av;
+ opts->num_pa_opts++;
+ return 0;
+}
+
static char *
parse_options(argc, argv, opts, progname)
int argc;
@@ -296,7 +331,7 @@ parse_options(argc, argv, opts, progname)
int use_k5 = 0;
int i;
- while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:v"))
+ while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:vX:"))
!= -1) {
switch (i) {
case 'V':
@@ -380,6 +415,14 @@ parse_options(argc, argv, opts, progname)
opts->k5_cache_name = optarg;
}
break;
+ case 'X':
+ code = add_preauth_opt(opts, optarg);
+ if (code)
+ {
+ com_err(progname, code, "while adding preauth option");
+ errflg++;
+ }
+ break;
#if 0
/*
A little more work is needed before we can enable this
@@ -752,12 +795,15 @@ k5_kinit(opts, k5)
krb5_keytab keytab = 0;
krb5_creds my_creds;
krb5_error_code code = 0;
- krb5_get_init_creds_opt options;
+ krb5_get_init_creds_opt *options = NULL;
+ int i;
if (!got_k5)
return 0;
- krb5_get_init_creds_opt_init(&options);
+ code = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
+ if (code)
+ goto cleanup;
memset(&my_creds, 0, sizeof(my_creds));
/*
@@ -766,17 +812,17 @@ k5_kinit(opts, k5)
*/
if (opts->lifetime)
- krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
+ krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
if (opts->rlife)
- krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife);
+ krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
if (opts->forwardable)
- krb5_get_init_creds_opt_set_forwardable(&options, 1);
+ krb5_get_init_creds_opt_set_forwardable(options, 1);
if (opts->not_forwardable)
- krb5_get_init_creds_opt_set_forwardable(&options, 0);
+ krb5_get_init_creds_opt_set_forwardable(options, 0);
if (opts->proxiable)
- krb5_get_init_creds_opt_set_proxiable(&options, 1);
+ krb5_get_init_creds_opt_set_proxiable(options, 1);
if (opts->not_proxiable)
- krb5_get_init_creds_opt_set_proxiable(&options, 0);
+ krb5_get_init_creds_opt_set_proxiable(options, 0);
if (opts->addresses)
{
krb5_address **addresses = NULL;
@@ -785,10 +831,10 @@ k5_kinit(opts, k5)
com_err(progname, code, "getting local addresses");
goto cleanup;
}
- krb5_get_init_creds_opt_set_address_list(&options, addresses);
+ krb5_get_init_creds_opt_set_address_list(options, addresses);
}
if (opts->no_addresses)
- krb5_get_init_creds_opt_set_address_list(&options, NULL);
+ krb5_get_init_creds_opt_set_address_list(options, NULL);
if ((opts->action == INIT_KT) && opts->keytab_name)
{
@@ -800,20 +846,49 @@ k5_kinit(opts, k5)
}
}
+ for (i = 0; i < opts->num_pa_opts; i++) {
+ code = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
+ opts->pa_opts[i].attr,
+ opts->pa_opts[i].value);
+ if (code != 0) {
+ com_err(progname, code, "while setting '%s'='%s'",
+ opts->pa_opts[i].attr, opts->pa_opts[i].value);
+ goto cleanup;
+ }
+ }
+
+#if 0 /* XXX Testing... */
+ code = krb5_get_init_creds_opt_set_pkinit(
+ k5->ctx, /* context */
+ options, /* get_init_creds_opt */
+ NULL, /* principal */
+ "/tmp/x509up_u20010", /* X509_user_identity */
+ "/etc/grid-security/certificates", /* X509_anchors */
+ NULL, /* X509_chain_list */
+ NULL, /* X509_revoke_list */
+ 0, /* flags */
+ NULL, /* prompter_fct */
+ NULL, /* prompter_data */
+ NULL); /* password */
+ if (code) {
+ com_err(progname, code, "while setting pkinit options");
+ goto cleanup;
+ }
+#endif
switch (opts->action) {
case INIT_PW:
code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
0, kinit_prompter, 0,
opts->starttime,
opts->service_name,
- &options);
+ options);
break;
case INIT_KT:
code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
keytab,
opts->starttime,
opts->service_name,
- &options);
+ options);
break;
case VALIDATE:
code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc,
@@ -876,9 +951,16 @@ k5_kinit(opts, k5)
notix = 0;
cleanup:
+ if (options)
+ krb5_get_init_creds_opt_free(k5->ctx, options);
if (my_creds.client == k5->me) {
my_creds.client = 0;
}
+ if (opts->pa_opts) {
+ free(opts->pa_opts);
+ opts->pa_opts = NULL;
+ opts->num_pa_opts = 0;
+ }
krb5_free_cred_contents(k5->ctx, &my_creds);
if (keytab)
krb5_kt_close(k5->ctx, keytab);
diff --git a/src/clients/kpasswd/kpasswd.c b/src/clients/kpasswd/kpasswd.c
index 95e33ff..204a8bf 100644
--- a/src/clients/kpasswd/kpasswd.c
+++ b/src/clients/kpasswd/kpasswd.c
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
krb5_principal princ;
char *pname;
krb5_ccache ccache;
- krb5_get_init_creds_opt opts;
+ krb5_get_init_creds_opt *opts = NULL;
krb5_creds creds;
char pw[1024];
@@ -102,26 +102,31 @@ int main(int argc, char *argv[])
get_name_from_passwd_file(argv[0], context, &princ);
}
- krb5_get_init_creds_opt_init(&opts);
- krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
- krb5_get_init_creds_opt_set_renew_life(&opts, 0);
- krb5_get_init_creds_opt_set_forwardable(&opts, 0);
- krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+ if ((ret = krb5_get_init_creds_opt_alloc(context, &opts))) {
+ com_err(argv[0], ret, "allocating krb5_get_init_creds_opt");
+ exit(1);
+ }
+ krb5_get_init_creds_opt_set_tkt_life(opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life(opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(opts, 0);
if ((ret = krb5_get_init_creds_password(context, &creds, princ, NULL,
krb5_prompter_posix, NULL,
- 0, "kadmin/changepw", &opts))) {
+ 0, "kadmin/changepw", opts))) {
if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
com_err(argv[0], 0,
"Password incorrect while getting initial ticket");
else
com_err(argv[0], ret, "getting initial ticket");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
pwlen = sizeof(pw);
if ((ret = krb5_read_password(context, P1, P2, pw, &pwlen))) {
com_err(argv[0], ret, "while reading password");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
@@ -129,6 +134,7 @@ int main(int argc, char *argv[])
&result_code, &result_code_string,
&result_string))) {
com_err(argv[0], ret, "changing password");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
@@ -138,6 +144,7 @@ int main(int argc, char *argv[])
result_string.length?": ":"",
(int) result_string.length,
result_string.data ? result_string.data : "");
+ krb5_get_init_creds_opt_free(context, opts);
exit(2);
}
@@ -145,6 +152,7 @@ int main(int argc, char *argv[])
free(result_string.data);
if (result_code_string.data != NULL)
free(result_code_string.data);
+ krb5_get_init_creds_opt_free(context, opts);
printf("Password changed.\n");
exit(0);
diff --git a/src/clients/kpasswd/ksetpwd.c b/src/clients/kpasswd/ksetpwd.c
index 148e686..2eec397 100644
--- a/src/clients/kpasswd/ksetpwd.c
+++ b/src/clients/kpasswd/ksetpwd.c
@@ -34,8 +34,6 @@ static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions )
{
krb5_preauthtype preauth[] = { KRB5_PADATA_ENC_TIMESTAMP };
krb5_enctype etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC};
- memset( outOptions, 0, sizeof(*outOptions) );
- krb5_get_init_creds_opt_init(outOptions);
krb5_get_init_creds_opt_set_address_list(outOptions, NULL);
krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) );
krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) );
@@ -128,17 +126,21 @@ static kbrccache_t userinitcontext(
}
if( kres != 0 || have_credentials == 0 )
{
- krb5_get_init_creds_opt options;
- get_init_creds_opt_init(&options);
+ krb5_get_init_creds_opt *options = NULL;
+ kres = krb5_get_init_creds_opt_alloc(kcontext, &options);
+ if ( kres == 0 )
+ {
+ get_init_creds_opt_init(options);
/*
** no valid credentials - get new ones
*/
- kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
- NULL /*prompter*/,
- NULL /*data*/,
- 0 /*starttime*/,
- 0 /*in_tkt_service*/,
- &options /*options*/ );
+ kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
+ NULL /*prompter*/,
+ NULL /*data*/,
+ 0 /*starttime*/,
+ 0 /*in_tkt_service*/,
+ options /*options*/ );
+ }
if( kres == 0 )
{
if( numCreds <= 0 )
@@ -148,6 +150,7 @@ static kbrccache_t userinitcontext(
if( kres == 0 )
have_credentials = 1;
}
+ krb5_get_init_creds_opt_free(kcontext, options);
}
#ifdef NOTUSED
if( have_credentials )
diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h
index 60c02cb..bf6073e 100644
--- a/src/include/k5-int-pkinit.h
+++ b/src/include/k5-int-pkinit.h
@@ -215,12 +215,12 @@ krb5_error_code encode_krb5_reply_key_pack
krb5_error_code encode_krb5_reply_key_pack_draft9
(const krb5_reply_key_pack_draft9 *, krb5_data **code);
-krb5_error_code encode_krb5_td_trusted_certifiers
- (const krb5_external_principal_identifier **, krb5_data **code);
-
krb5_error_code encode_krb5_typed_data
(const krb5_typed_data **, krb5_data **code);
+krb5_error_code encode_krb5_td_trusted_certifiers
+ (const krb5_external_principal_identifier **, krb5_data **code);
+
krb5_error_code encode_krb5_td_dh_parameters
(const krb5_algorithm_identifier **, krb5_data **code);
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 2eac815..1d89355 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -891,51 +891,17 @@ typedef struct _krb5_preauth_context {
krb5_enctype *enctypes;
/* The plugin's per-plugin context and a function to clear it. */
void *plugin_context;
- void (*client_fini)(krb5_context context, void *plugin_context);
+ preauth_client_plugin_fini_proc client_fini;
/* The module's table, and some of its members, copied here for
* convenience when we populated the list. */
struct krb5plugin_preauth_client_ftable_v0 *ftable;
const char *name;
int flags, use_count;
- krb5_error_code (*client_process)(krb5_context context,
- void *plugin_context,
- void *request_context,
- preauth_get_client_data_proc get_data_proc,
- krb5_preauth_client_rock *rock,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data *pa_data,
- krb5_prompter_fct prompter,
- void *prompter_data,
- preauth_get_as_key_proc gak_fct,
- void *gak_data,
- krb5_data *salt,
- krb5_data *s2kparams,
- krb5_keyblock *as_key,
- krb5_pa_data **out_pa_data);
- krb5_error_code (*client_tryagain)(krb5_context context,
- void *plugin_context,
- void *request_context,
- preauth_get_client_data_proc get_data_proc,
- krb5_preauth_client_rock *rock,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data *old_pa_data,
- krb5_error *err_reply,
- krb5_prompter_fct prompter,
- void *prompter_data,
- preauth_get_as_key_proc gak_fct,
- void *gak_data,
- krb5_data *salt,
- krb5_data *s2kparams,
- krb5_keyblock *as_key,
- krb5_pa_data **new_pa_data);
- void (*client_req_init)(krb5_context context, void *plugin_context,
- void **request_context);
- void (*client_req_fini)(krb5_context context, void *plugin_context,
- void *request_context);
+ preauth_client_process_proc client_process;
+ preauth_client_tryagain_proc client_tryagain;
+ preauth_client_supply_gic_opts_proc client_supply_gic_opts;
+ preauth_client_request_init_proc client_req_init;
+ preauth_client_request_fini_proc client_req_fini;
/* The per-request context which the client_req_init() function
* might allocate, which we'll need to clean up later by
* calling the client_req_fini() function. */
@@ -1038,6 +1004,74 @@ void krb5_free_etype_info
/*
* End "preauth.h"
*/
+
+/*
+ * Extending the krb5_get_init_creds_opt structure. The original
+ * krb5_get_init_creds_opt structure is defined publicly. The
+ * new extended version is private. The original interface
+ * assumed a pre-allocated structure which was passed to
+ * krb5_get_init_creds_init(). The new interface assumes that
+ * the caller will call krb5_get_init_creds_alloc() and
+ * krb5_get_init_creds_free().
+ *
+ * Callers MUST NOT call krb5_get_init_creds_init() after allocating an
+ * opts structure using krb5_get_init_creds_alloc(). To do so will
+ * introduce memory leaks. Unfortunately, there is no way to enforce
+ * this behavior.
+ *
+ * Two private flags are added for backward compatibility.
+ * KRB5_GET_INIT_CREDS_OPT_EXTENDED says that the structure was allocated
+ * with the new krb5_get_init_creds_opt_alloc() function.
+ * KRB5_GET_INIT_CREDS_OPT_SHADOWED is set to indicate that the extended
+ * structure is a shadow copy of an original krb5_get_init_creds_opt
+ * structure.
+ * If KRB5_GET_INIT_CREDS_OPT_SHADOWED is set after a call to
+ * krb5int_gic_opt_to_opte(), the resulting extended structure should be
+ * freed (using krb5_get_init_creds_free). Otherwise, the original
+ * structure was already extended and there is no need to free it.
+ */
+
+#define KRB5_GET_INIT_CREDS_OPT_EXTENDED 0x80000000
+#define KRB5_GET_INIT_CREDS_OPT_SHADOWED 0x40000000
+
+#define krb5_gic_opt_is_extended(s) \
+ (((s)->flags & KRB5_GET_INIT_CREDS_OPT_EXTENDED) ? 1 : 0)
+#define krb5_gic_opt_is_shadowed(s) \
+ (((s)->flags & KRB5_GET_INIT_CREDS_OPT_SHADOWED) ? 1 : 0)
+
+
+typedef struct _krb5_gic_opt_private {
+ int num_preauth_data;
+ krb5_gic_opt_pa_data *preauth_data;
+} krb5_gic_opt_private;
+
+typedef struct _krb5_gic_opt_ext {
+ krb5_flags flags;
+ krb5_deltat tkt_life;
+ krb5_deltat renew_life;
+ int forwardable;
+ int proxiable;
+ krb5_enctype *etype_list;
+ int etype_list_length;
+ krb5_address **address_list;
+ krb5_preauthtype *preauth_list;
+ int preauth_list_length;
+ krb5_data *salt;
+ /*
+ * Do not change anything above this point in this structure.
+ * It is identical to the public krb5_get_init_creds_opt structure.
+ * New members must be added below.
+ */
+ krb5_gic_opt_private *opt_private;
+} krb5_gic_opt_ext;
+
+krb5_error_code
+krb5int_gic_opt_to_opte(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte,
+ unsigned int force,
+ const char *where);
+
krb5_error_code
krb5int_copy_data_contents (krb5_context, const krb5_data *, krb5_data *);
@@ -1061,14 +1095,14 @@ krb5_get_init_creds
void *prompter_data,
krb5_deltat start_time,
char *in_tkt_service,
- krb5_get_init_creds_opt *gic_options,
+ krb5_gic_opt_ext *gic_options,
krb5_gic_get_as_key_fct gak,
void *gak_data,
int *master,
krb5_kdc_rep **as_reply);
-void krb5int_populate_gic_opt (
- krb5_context, krb5_get_init_creds_opt *,
+krb5_error_code krb5int_populate_gic_opt (
+ krb5_context, krb5_gic_opt_ext **,
krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
krb5_preauthtype *pre_auth_types, krb5_creds *creds);
@@ -1083,7 +1117,8 @@ krb5_error_code KRB5_CALLCONV krb5_do_preauth
krb5_enctype *etype, krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock);
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte);
krb5_error_code KRB5_CALLCONV krb5_do_preauth_tryagain
(krb5_context context,
krb5_kdc_req *request,
@@ -1095,7 +1130,8 @@ krb5_error_code KRB5_CALLCONV krb5_do_preauth_tryagain
krb5_enctype *etype, krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock);
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte);
void KRB5_CALLCONV krb5_init_preauth_context
(krb5_context);
void KRB5_CALLCONV krb5_free_preauth_context
@@ -1103,7 +1139,7 @@ void KRB5_CALLCONV krb5_free_preauth_context
void KRB5_CALLCONV krb5_clear_preauth_context_use_counts
(krb5_context);
void KRB5_CALLCONV krb5_preauth_prepare_request
- (krb5_context, krb5_get_init_creds_opt *, krb5_kdc_req *);
+ (krb5_context, krb5_gic_opt_ext *, krb5_kdc_req *);
void KRB5_CALLCONV krb5_preauth_request_context_init
(krb5_context);
void KRB5_CALLCONV krb5_preauth_request_context_fini
@@ -1814,7 +1850,7 @@ void krb5int_free_srv_dns_data(struct srv_dns_entry *);
/* To keep happy libraries which are (for now) accessing internal stuff */
/* Make sure to increment by one when changing the struct */
-#define KRB5INT_ACCESS_STRUCT_VERSION 10
+#define KRB5INT_ACCESS_STRUCT_VERSION 11
#ifndef ANAME_SZ
struct ktext; /* from krb.h, for krb524 support */
@@ -1868,6 +1904,62 @@ typedef struct _krb5int_access {
struct _krb5_key_data **out,
krb5_int16 *n_key_data,
int *mkvno);
+
+ /*
+ * pkinit asn.1 encode/decode functions
+ */
+ krb5_error_code (*encode_krb5_auth_pack)
+ (const krb5_auth_pack *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_auth_pack_draft9)
+ (const krb5_auth_pack_draft9 *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_kdc_dh_key_info)
+ (const krb5_kdc_dh_key_info *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_pa_pk_as_rep)
+ (const krb5_pa_pk_as_rep *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_pa_pk_as_rep_draft9)
+ (const krb5_pa_pk_as_rep_draft9 *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_pa_pk_as_req)
+ (const krb5_pa_pk_as_req *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_pa_pk_as_req_draft9)
+ (const krb5_pa_pk_as_req_draft9 *rep, krb5_data **code);
+ krb5_error_code (*encode_krb5_reply_key_pack)
+ (const krb5_reply_key_pack *, krb5_data **code);
+ krb5_error_code (*encode_krb5_reply_key_pack_draft9)
+ (const krb5_reply_key_pack_draft9 *, krb5_data **code);
+ krb5_error_code (*encode_krb5_td_dh_parameters)
+ (const krb5_algorithm_identifier **, krb5_data **code);
+ krb5_error_code (*encode_krb5_td_trusted_certifiers)
+ (const krb5_external_principal_identifier **, krb5_data **code);
+ krb5_error_code (*encode_krb5_typed_data)
+ (const krb5_typed_data **, krb5_data **code);
+
+ krb5_error_code (*decode_krb5_auth_pack)
+ (const krb5_data *, krb5_auth_pack **);
+ krb5_error_code (*decode_krb5_auth_pack_draft9)
+ (const krb5_data *, krb5_auth_pack_draft9 **);
+ krb5_error_code (*decode_krb5_pa_pk_as_req)
+ (const krb5_data *, krb5_pa_pk_as_req **);
+ krb5_error_code (*decode_krb5_pa_pk_as_req_draft9)
+ (const krb5_data *, krb5_pa_pk_as_req_draft9 **);
+ krb5_error_code (*decode_krb5_pa_pk_as_rep)
+ (const krb5_data *, krb5_pa_pk_as_rep **);
+ krb5_error_code (*decode_krb5_pa_pk_as_rep_draft9)
+ (const krb5_data *, krb5_pa_pk_as_rep_draft9 **);
+ krb5_error_code (*decode_krb5_kdc_dh_key_info)
+ (const krb5_data *, krb5_kdc_dh_key_info **);
+ krb5_error_code (*decode_krb5_principal_name)
+ (const krb5_data *, krb5_principal_data **);
+ krb5_error_code (*decode_krb5_reply_key_pack)
+ (const krb5_data *, krb5_reply_key_pack **);
+ krb5_error_code (*decode_krb5_reply_key_pack_draft9)
+ (const krb5_data *, krb5_reply_key_pack_draft9 **);
+ krb5_error_code (*decode_krb5_td_dh_parameters)
+ (const krb5_data *, krb5_algorithm_identifier ***);
+ krb5_error_code (*decode_krb5_td_trusted_certifiers)
+ (const krb5_data *, krb5_external_principal_identifier ***);
+ krb5_error_code (*decode_krb5_typed_data)
+ (const krb5_data *, krb5_typed_data ***);
+
} krb5int_access;
#define KRB5INT_ACCESS_VERSION \
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 424325f..24b9476 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -2437,6 +2437,16 @@ typedef struct _krb5_get_init_creds_opt {
#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_alloc
+(krb5_context context,
+ krb5_get_init_creds_opt **opt);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free
+(krb5_context context,
+ krb5_get_init_creds_opt *opt);
+
void KRB5_CALLCONV
krb5_get_init_creds_opt_init
(krb5_get_init_creds_opt *opt);
@@ -2484,6 +2494,26 @@ krb5_get_init_creds_opt_set_salt
krb5_data *salt);
+/* Generic preauth option attribute/value pairs */
+typedef struct _krb5_gic_opt_pa_data {
+ char *attr;
+ char *value;
+} krb5_gic_opt_pa_data;
+
+/*
+ * This function allows the caller to supply options to preauth
+ * plugins. Preauth plugin modules are given a chance to look
+ * at each option at the time this function is called in ordre
+ * to check the validity of the option.
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pa
+ (krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value);
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password
diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index f8a9db1..4307f6e 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -93,34 +93,30 @@ struct _krb5_preauth_client_rock;
* which gets sent over the wire. */
#define PA_PSEUDO 0x00000080
+
+/***************************************************************************
+ *
+ * Client-side preauthentication plugin interface definition.
+ *
+ ***************************************************************************/
+
/*
- * A server module's callback functions are allowed to request specific types
- * of information about the given client or server record or request, even
- * though the database records themselves are opaque to the module.
+ * A callback which will obtain the user's long-term AS key by prompting the
+ * user for the password, then salting it properly, and so on. For the moment,
+ * it's identical to the get_as_key callback used inside of libkrb5, but we
+ * define a new typedef here instead of making the existing one public to
+ * isolate ourselves from potential future changes.
*/
-enum krb5plugin_preauth_entry_request_type {
- /* The returned krb5_data item holds a DER-encoded X.509 certificate. */
- krb5plugin_preauth_entry_request_certificate = 1,
- /* The returned krb5_data_item holds a krb5_deltat. */
- krb5plugin_preauth_entry_max_time_skew = 2,
- /* The returned krb5_data_item holds an array of krb5_keyblock structures,
- * terminated by an entry with key type = 0.
- * Each keyblock should have its contents freed in turn, and then the data
- * item itself should be freed. */
- krb5plugin_preauth_keys = 3,
- /* The returned krb5_data_item holds the request structure, re-encoded
- * using DER. Unless the client implementation is the same as the server
- * implementation, there's a good chance that the result will not match
- * what the client sent, so don't go creating any fatal errors if it
- * doesn't match up. */
- krb5plugin_preauth_request_body = 4
-};
typedef krb5_error_code
-(*preauth_get_entry_data_proc)(krb5_context,
- krb5_kdc_req *,
- struct _krb5_db_entry_new *,
- krb5_int32 request_type,
- krb5_data **);
+(*preauth_get_as_key_proc)(krb5_context,
+ krb5_principal,
+ krb5_enctype,
+ krb5_prompter_fct,
+ void *prompter_data,
+ krb5_data *salt,
+ krb5_data *s2kparams,
+ krb5_keyblock *as_key,
+ void *gak_data);
/*
* A client module's callback functions are allowed to request various
@@ -139,24 +135,102 @@ typedef krb5_error_code
krb5_int32 request_type,
krb5_data **);
+/* Per-plugin initialization/cleanup. The init function is called
+ * by libkrb5 when the plugin is loaded, and the fini function is
+ * called before the plugin is unloaded. Both are optional and
+ * may be called multiple times in case the plugin is used in
+ * multiple contexts. The returned context lives the lifetime of
+ * the krb5_context */
+typedef krb5_error_code
+(*preauth_client_plugin_init_proc)(krb5_context context,
+ void **plugin_context);
+typedef void
+(*preauth_client_plugin_fini_proc)(krb5_context context,
+ void *plugin_context);
+
+/* A callback which returns flags indicating if the module is a "real" or
+ * an "info" mechanism, and so on. This function is called for each entry
+ * in the client_pa_type_list. */
+typedef int
+(*preauth_client_get_flags_proc)(krb5_context context,
+ krb5_preauthtype pa_type);
+
+/* Per-request initialization/cleanup. The request_init function is
+ * called when beginning to process a get_init_creds request and the
+ * request_fini function is called when processing of the request is
+ * complete. This is optional. It may be called multiple times in
+ * the lifetime of a krb5_context. */
+typedef void
+(*preauth_client_request_init_proc)(krb5_context context,
+ void *plugin_context,
+ void **request_context);
+typedef void
+(*preauth_client_request_fini_proc)(krb5_context context,
+ void *plugin_context,
+ void *request_context);
+
+/* Client function which processes server-supplied data in pa_data,
+ * returns created data in out_pa_data, storing any of its own state in
+ * client_context if data for the associated preauthentication type is
+ * needed. It is also called after the AS-REP is received if the AS-REP
+ * includes preauthentication data of the associated type.
+ * NOTE! the encoded_previous_request will be NULL the first time this
+ * function is called, because it is expected to only ever contain the data
+ * obtained from a previous call to this function. */
+typedef krb5_error_code
+(*preauth_client_process_proc)(krb5_context context,
+ void *plugin_context,
+ void *request_context,
+ krb5_get_init_creds_opt *opt,
+ preauth_get_client_data_proc get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
+ krb5_kdc_req *request,
+ krb5_data *encoded_request_body,
+ krb5_data *encoded_previous_request,
+ krb5_pa_data *pa_data,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ preauth_get_as_key_proc gak_fct,
+ void *gak_data,
+ krb5_data *salt, krb5_data *s2kparams,
+ krb5_keyblock *as_key,
+ krb5_pa_data **out_pa_data);
+
+/* Client function which can attempt to use e-data in the error response to
+ * try to recover from the given error. If this function is not NULL, and
+ * it stores data in out_pa_data which is different data from the contents
+ * of in_pa_data, then the client library will retransmit the request. */
+typedef krb5_error_code
+(*preauth_client_tryagain_proc)(krb5_context context,
+ void *plugin_context,
+ void *request_context,
+ krb5_get_init_creds_opt *opt,
+ preauth_get_client_data_proc get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
+ krb5_kdc_req *request,
+ krb5_data *encoded_request_body,
+ krb5_data *encoded_previous_request,
+ krb5_pa_data *in_pa_data,
+ krb5_error *error,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ preauth_get_as_key_proc gak_fct,
+ void *gak_data,
+ krb5_data *salt, krb5_data *s2kparams,
+ krb5_keyblock *as_key,
+ krb5_pa_data **out_pa_data);
+
/*
- * A callback which will obtain the user's long-term AS key by prompting the
- * user for the password, then salting it properly, and so on. For the moment,
- * it's identical to the get_as_key callback used inside of libkrb5, but we
- * define a new typedef here instead of making the existing one public to
- * isolate ourselves from potential future changes.
+ * Client function which receives krb5_get_init_creds_opt information.
+ * The attr and value information supplied should be copied locally by
+ * the module if it wishes to reference it after returning from this call.
*/
typedef krb5_error_code
-(*preauth_get_as_key_proc)(krb5_context,
- krb5_principal,
- krb5_enctype,
- krb5_prompter_fct,
- void *prompter_data,
- krb5_data *salt,
- krb5_data *s2kparams,
- krb5_keyblock *as_key,
- void *gak_data);
-
+(*preauth_client_supply_gic_opts_proc)(krb5_context context,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value);
/*
* The function table / structure which a preauth client module must export as
* "preauthentication_client_0". If the interfaces work correctly, future
@@ -181,21 +255,22 @@ typedef struct krb5plugin_preauth_client_ftable_v0 {
* may be called multiple times in case the plugin is used in
* multiple contexts. The returned context lives the lifetime of
* the krb5_context */
- krb5_error_code (*init)(krb5_context context, void **plugin_context);
- void (*fini)(krb5_context context, void *plugin_context);
+ preauth_client_plugin_init_proc init;
+ preauth_client_plugin_fini_proc fini;
+
/* A callback which returns flags indicating if the module is a "real" or
* an "info" mechanism, and so on. This function is called for each entry
* in the client_pa_type_list. */
- int (*flags)(krb5_context context, krb5_preauthtype pa_type);
+ preauth_client_get_flags_proc flags;
+
/* Per-request initialization/cleanup. The request_init function is
* called when beginning to process a get_init_creds request and the
* request_fini function is called when processing of the request is
* complete. This is optional. It may be called multiple times in
* the lifetime of a krb5_context. */
- void (*request_init)(krb5_context context, void *plugin_context,
- void **request_context);
- void (*request_fini)(krb5_context context, void *plugin_context,
- void *request_context);
+ preauth_client_request_init_proc request_init;
+ preauth_client_request_fini_proc request_fini;
+
/* Client function which processes server-supplied data in pa_data,
* returns created data in out_pa_data, storing any of its own state in
* client_context if data for the associated preauthentication type is
@@ -204,45 +279,136 @@ typedef struct krb5plugin_preauth_client_ftable_v0 {
* NOTE! the encoded_previous_request will be NULL the first time this
* function is called, because it is expected to only ever contain the data
* obtained from a previous call to this function. */
- krb5_error_code (*process)(krb5_context context,
- void *plugin_context,
- void *request_context,
- preauth_get_client_data_proc get_data_proc,
- struct _krb5_preauth_client_rock *rock,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data *pa_data,
- krb5_prompter_fct prompter,
- void *prompter_data,
- preauth_get_as_key_proc gak_fct,
- void *gak_data,
- krb5_data *salt, krb5_data *s2kparams,
- krb5_keyblock *as_key,
- krb5_pa_data **out_pa_data);
+ preauth_client_process_proc process;
+
/* Client function which can attempt to use e-data in the error response to
* try to recover from the given error. If this function is not NULL, and
* it stores data in out_pa_data which is different data from the contents
* of in_pa_data, then the client library will retransmit the request. */
- krb5_error_code (*tryagain)(krb5_context context,
- void *plugin_context,
- void *request_context,
- preauth_get_client_data_proc get_data_proc,
- struct _krb5_preauth_client_rock *rock,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data *in_pa_data,
- krb5_error *error,
- krb5_prompter_fct prompter,
- void *prompter_data,
- preauth_get_as_key_proc gak_fct,
- void *gak_data,
- krb5_data *salt, krb5_data *s2kparams,
- krb5_keyblock *as_key,
- krb5_pa_data **out_pa_data);
+ preauth_client_tryagain_proc tryagain;
+
+ /*
+ * Client function which receives krb5_get_init_creds_opt information.
+ * The attr and value information supplied should be copied locally by
+ * the module if it wishes to reference it after returning from this call.
+ */
+ preauth_client_supply_gic_opts_proc gic_opts;
} krb5plugin_preauth_client_ftable_v0;
+/***************************************************************************
+ *
+ * Server-side preauthentication plugin interface definition.
+ *
+ ***************************************************************************/
+
+/*
+ * A server module's callback functions are allowed to request specific types
+ * of information about the given client or server record or request, even
+ * though the database records themselves are opaque to the module.
+ */
+enum krb5plugin_preauth_entry_request_type {
+ /* The returned krb5_data item holds a DER-encoded X.509 certificate. */
+ krb5plugin_preauth_entry_request_certificate = 1,
+ /* The returned krb5_data_item holds a krb5_deltat. */
+ krb5plugin_preauth_entry_max_time_skew = 2,
+ /* The returned krb5_data_item holds an array of krb5_keyblock structures,
+ * terminated by an entry with key type = 0.
+ * Each keyblock should have its contents freed in turn, and then the data
+ * item itself should be freed. */
+ krb5plugin_preauth_keys = 3,
+ /* The returned krb5_data_item holds the request structure, re-encoded
+ * using DER. Unless the client implementation is the same as the server
+ * implementation, there's a good chance that the result will not match
+ * what the client sent, so don't go creating any fatal errors if it
+ * doesn't match up. */
+ krb5plugin_preauth_request_body = 4
+};
+
+typedef krb5_error_code
+(*preauth_get_entry_data_proc)(krb5_context,
+ krb5_kdc_req *,
+ struct _krb5_db_entry_new *,
+ krb5_int32 request_type,
+ krb5_data **);
+
+/* Preauth plugin initialization function */
+typedef krb5_error_code
+(*preauth_server_init_proc)(krb5_context context, void **plugin_context);
+
+/* Preauth plugin cleanup function */
+typedef void
+(*preauth_server_fini_proc)(krb5_context context, void *plugin_context);
+
+/* Return the flags which the KDC should use for this module. This is a
+ * callback instead of a static value because the module may or may not
+ * wish to count itself as a hardware preauthentication module (in other
+ * words, the flags may be affected by the configuration, for example if a
+ * site administrator can force a particular preauthentication type to be
+ * supported using only hardware). This function is called for each entry
+ * entry in the server_pa_type_list. */
+typedef int
+(*preauth_server_flags_proc)(krb5_context context, krb5_preauthtype patype);
+
+/* Get preauthentication data to send to the client as part of the "you
+ * need to use preauthentication" error. The module doesn't need to
+ * actually provide data if the protocol doesn't require it, but it should
+ * return either zero or non-zero to control whether its padata type is
+ * included in the list which is sent back to the client. Is not allowed
+ * to create a context because we have no guarantee that the client will
+ * ever call again (or that it will hit this server if it does), in which
+ * case a context might otherwise hang around forever. */
+typedef krb5_error_code
+(*preauth_server_edata_proc)(krb5_context,
+ krb5_kdc_req *request,
+ struct _krb5_db_entry_new *client,
+ struct _krb5_db_entry_new *server,
+ preauth_get_entry_data_proc,
+ void *pa_module_context,
+ krb5_pa_data *data);
+
+/* Verify preauthentication data sent by the client, setting the
+ * TKT_FLG_PRE_AUTH or TKT_FLG_HW_AUTH flag in the enc_tkt_reply's "flags"
+ * field as appropriate, and returning nonzero on failure. Can create
+ * context data for consumption by the return_proc or freepa_proc below. */
+typedef krb5_error_code
+(*preauth_server_verify_proc)(krb5_context context,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply,
+ krb5_pa_data *data,
+ preauth_get_entry_data_proc,
+ void *pa_module_context,
+ void **pa_request_context,
+ krb5_data **e_data);
+
+/* Generate preauthentication response data to send to the client as part
+ * of the AS-REP. If it needs to override the key which is used to encrypt
+ * the response, it can do so. The module is expected (but not required,
+ * if a freepa_proc is also provided) to free any context data it saved in
+ * "request_pa_context". */
+typedef krb5_error_code
+(*preauth_server_return_proc)(krb5_context context,
+ krb5_pa_data * padata,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *reply,
+ struct _krb5_key_data *client_keys,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **send_pa,
+ preauth_get_entry_data_proc,
+ void *pa_module_context,
+ void **pa_request_context);
+
+/* Free up the server-side per-request context, in cases where
+ * server_return_proc() didn't or for whatever reason was not called.
+ * Can be NULL. */
+typedef krb5_error_code
+(*preauth_server_free_reqcontext_proc)(krb5_context,
+ void *pa_module_context,
+ void **request_pa_context);
+
/*
* The function table / structure which a preauth server module must export as
* "preauthentication_server_0". NOTE: replace "0" with "1" for the type and
@@ -262,8 +428,9 @@ typedef struct krb5plugin_preauth_server_ftable_v0 {
/* Per-plugin initialization/cleanup. The init function is called by the
* KDC when the plugin is loaded, and the fini function is called before
* the plugin is unloaded. Both are optional. */
- krb5_error_code (*init_proc)(krb5_context, void **);
- void (*fini_proc)(krb5_context, void *);
+ preauth_server_init_proc init_proc;
+ preauth_server_fini_proc fini_proc;
+
/* Return the flags which the KDC should use for this module. This is a
* callback instead of a static value because the module may or may not
* wish to count itself as a hardware preauthentication module (in other
@@ -271,7 +438,8 @@ typedef struct krb5plugin_preauth_server_ftable_v0 {
* site administrator can force a particular preauthentication type to be
* supported using only hardware). This function is called for each entry
* entry in the server_pa_type_list. */
- int (*flags_proc)(krb5_context, krb5_preauthtype);
+ preauth_server_flags_proc flags_proc;
+
/* Get preauthentication data to send to the client as part of the "you
* need to use preauthentication" error. The module doesn't need to
* actually provide data if the protocol doesn't require it, but it should
@@ -280,47 +448,52 @@ typedef struct krb5plugin_preauth_server_ftable_v0 {
* to create a context because we have no guarantee that the client will
* ever call again (or that it will hit this server if it does), in which
* case a context might otherwise hang around forever. */
- krb5_error_code (*edata_proc)(krb5_context, krb5_kdc_req *request,
- struct _krb5_db_entry_new *client,
- struct _krb5_db_entry_new *server,
- preauth_get_entry_data_proc,
- void *pa_module_context,
- krb5_pa_data *data);
+ preauth_server_edata_proc edata_proc;
+
/* Verify preauthentication data sent by the client, setting the
* TKT_FLG_PRE_AUTH or TKT_FLG_HW_AUTH flag in the enc_tkt_reply's "flags"
* field as appropriate, and returning nonzero on failure. Can create
* context data for consumption by the return_proc or freepa_proc below. */
- krb5_error_code (*verify_proc)(krb5_context,
- struct _krb5_db_entry_new *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_enc_tkt_part *enc_tkt_reply,
- krb5_pa_data *data,
- preauth_get_entry_data_proc,
- void *pa_module_context,
- void **pa_request_context,
- krb5_data **e_data);
+ preauth_server_verify_proc verify_proc;
+
/* Generate preauthentication response data to send to the client as part
* of the AS-REP. If it needs to override the key which is used to encrypt
* the response, it can do so. The module is expected (but not required,
* if a freepa_proc is also provided) to free any context data it saved in
* "request_pa_context". */
- krb5_error_code (*return_proc)(krb5_context, krb5_pa_data * padata,
- struct _krb5_db_entry_new *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_kdc_rep *reply,
- struct _krb5_key_data *client_keys,
- krb5_keyblock *encrypting_key,
- krb5_pa_data **send_pa,
- preauth_get_entry_data_proc,
- void *pa_module_context,
- void **pa_request_context);
+ preauth_server_return_proc return_proc;
+
/* Free up the server-side per-request context, in cases where
- * server_return_proc() didn't or for whatever reason was not called. Can
- * be NULL. */
- krb5_error_code (*freepa_reqcontext_proc)(krb5_context,
- void *pa_module_context,
- void **request_pa_context);
+ * server_return_proc() didn't or for whatever reason was not called.
+ * Can be NULL. */
+ preauth_server_free_reqcontext_proc freepa_reqcontext_proc;
+
} krb5plugin_preauth_server_ftable_v0;
+
+
+/*
+ * This function allows a preauth plugin to obtain preauth
+ * options. The preauth_data returned from this function
+ * should be freed by calling krb5_get_init_creds_opt_free_pa().
+ *
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_get_pa
+ (krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ int *num_preauth_data,
+ krb5_gic_opt_pa_data **preauth_data);
+
+/*
+ * This function frees the preauth_data that was returned by
+ * krb5_get_init_creds_opt_get_pa().
+ */
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free_pa
+ (krb5_context context,
+ int num_preauth_data,
+ krb5_gic_opt_pa_data *preauth_data);
+
#endif /* KRB5_PREAUTH_PLUGIN_H_INCLUDED */
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 7d06d99..67b7226 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -77,54 +77,17 @@ typedef des_cblock mit_des_cblock;
extern void mit_des_fixup_key_parity (mit_des_cblock );
extern int mit_des_is_weak_key (mit_des_cblock );
-typedef krb5_error_code (*verify_proc)
- (krb5_context, krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context,
- krb5_data **e_data);
-
-typedef krb5_error_code (*edata_proc)
- (krb5_context, krb5_kdc_req *request,
- krb5_db_entry *client, krb5_db_entry *server,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- krb5_pa_data *data);
-
-typedef krb5_error_code (*return_proc)
- (krb5_context, krb5_pa_data * padata,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request, krb5_kdc_rep *reply,
- krb5_key_data *client_key,
- krb5_keyblock *encrypting_key,
- krb5_pa_data **send_pa,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context);
-
-typedef krb5_error_code (*freepa_proc)
- (krb5_context, void *pa_module_context, void **pa_request_context);
-
-typedef krb5_error_code (*init_proc)
- (krb5_context, void **);
-typedef void (*fini_proc)
- (krb5_context, void *);
-
typedef struct _krb5_preauth_systems {
const char *name;
int type;
int flags;
void *plugin_context;
- init_proc init;
- fini_proc fini;
- edata_proc get_edata;
- verify_proc verify_padata;
- return_proc return_padata;
- freepa_proc free_pa_request_context;
+ preauth_server_init_proc init;
+ preauth_server_fini_proc fini;
+ preauth_server_edata_proc get_edata;
+ preauth_server_verify_proc verify_padata;
+ preauth_server_return_proc return_padata;
+ preauth_server_free_reqcontext_proc free_pa_reqctx;
} krb5_preauth_systems;
static krb5_error_code verify_enc_timestamp
@@ -305,7 +268,7 @@ load_preauth_plugins(krb5_context context)
struct krb5plugin_preauth_server_ftable_v0 *ftable;
int module_count, i, j, k;
void *plugin_context;
- init_proc server_init_proc = NULL;
+ preauth_server_init_proc server_init_proc = NULL;
memset(&err, 0, sizeof(err));
@@ -428,7 +391,7 @@ load_preauth_plugins(krb5_context context)
preauth_systems[k].get_edata = ftable->edata_proc;
preauth_systems[k].verify_padata = ftable->verify_proc;
preauth_systems[k].return_padata = ftable->return_proc;
- preauth_systems[k].free_pa_request_context =
+ preauth_systems[k].free_pa_reqctx =
ftable->freepa_reqcontext_proc;
k++;
}
@@ -527,10 +490,9 @@ free_padata_context(krb5_context kcontext, void **padata_context)
if (context->contexts[i].pa_context != NULL) {
preauth_system = context->contexts[i].pa_system;
mctx = preauth_system->plugin_context;
- if (preauth_system->free_pa_request_context != NULL) {
+ if (preauth_system->free_pa_reqctx != NULL) {
pctx = &context->contexts[i].pa_context;
- (*preauth_system->free_pa_request_context)(kcontext, mctx,
- pctx);
+ (*preauth_system->free_pa_reqctx)(kcontext, mctx, pctx);
}
context->contexts[i].pa_context = NULL;
}
diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c
index 9ccbffd..0b739bd 100644
--- a/src/lib/krb5/asn.1/asn1_k_decode.c
+++ b/src/lib/krb5/asn.1/asn1_k_decode.c
@@ -1653,7 +1653,17 @@ asn1_error_code asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
}
#endif
+#if 0
opt_field(val->supportedCMSTypes, 2, asn1_decode_sequence_of_AlgorithmIdentifier, NULL);
+#else
+ if (asn1buf_remains(&subbuf, seqindef)) {
+ if (tagnum == 2) {
+ asn1_decode_sequence_of_AlgorithmIdentifier(&subbuf,val->supportedCMSTypes);
+ if (!taglen && indef) { get_eoc(); }
+ next_tag();
+ } else val->supportedCMSTypes = NULL;
+ }
+#endif
opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
end_structure();
}
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index 0add915..111f61d 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -1010,7 +1010,6 @@ asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *b
asn1_error_code asn1_encode_pk_authenticator(asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen)
{
asn1_setup();
-
asn1_addlenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_encode_octetstring);
asn1_addfield(val->nonce, 2, asn1_encode_integer);
asn1_addfield(val->ctime, 1, asn1_encode_kerberos_time);
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 80baf41..598354b 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -843,7 +843,7 @@ krb5_get_init_creds(krb5_context context,
void *prompter_data,
krb5_deltat start_time,
char *in_tkt_service,
- krb5_get_init_creds_opt *options,
+ krb5_gic_opt_ext *options,
krb5_gic_get_as_key_fct gak_fct,
void *gak_data,
int *use_master,
@@ -1111,7 +1111,7 @@ krb5_get_init_creds(krb5_context context,
&salt, &s2kparams, &etype, &as_key,
prompter, prompter_data,
gak_fct, gak_data,
- &get_data_rock)))
+ &get_data_rock, options)))
goto cleanup;
} else {
/* retrying after an error other than PREAUTH_NEEDED, using e-data
@@ -1125,7 +1125,7 @@ krb5_get_init_creds(krb5_context context,
&salt, &s2kparams, &etype, &as_key,
prompter, prompter_data,
gak_fct, gak_data,
- &get_data_rock)) {
+ &get_data_rock, options)) {
/* couldn't come up with anything better */
ret = err_reply->error + ERROR_TABLE_BASE_krb5;
krb5_free_error(context, err_reply);
@@ -1206,7 +1206,7 @@ krb5_get_init_creds(krb5_context context,
local_as_reply->padata, &kdc_padata,
&salt, &s2kparams, &etype, &as_key, prompter,
prompter_data, gak_fct, gak_data,
- &get_data_rock)))
+ &get_data_rock, options)))
goto cleanup;
/* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
diff --git a/src/lib/krb5/krb/gic_keytab.c b/src/lib/krb5/krb/gic_keytab.c
index ba704e6..cae0495 100644
--- a/src/lib/krb5/krb/gic_keytab.c
+++ b/src/lib/krb5/krb/gic_keytab.c
@@ -76,11 +76,18 @@ krb5_get_as_key_keytab(
}
krb5_error_code KRB5_CALLCONV
-krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_keytab arg_keytab, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
+krb5_get_init_creds_keytab(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ krb5_keytab arg_keytab,
+ krb5_deltat start_time,
+ char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
{
krb5_error_code ret, ret2;
int use_master;
krb5_keytab keytab;
+ krb5_gic_opt_ext *opte = NULL;
if (arg_keytab == NULL) {
if ((ret = krb5_kt_default(context, &keytab)))
@@ -89,12 +96,17 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
keytab = arg_keytab;
}
+ ret = krb5int_gic_opt_to_opte(context, options, &opte, 1,
+ "krb5_get_init_creds_keytab");
+ if (ret)
+ return ret;
+
use_master = 0;
/* first try: get the requested tkt from any kdc */
ret = krb5_get_init_creds(context, creds, client, NULL, NULL,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_keytab, (void *) keytab,
&use_master,NULL);
@@ -115,7 +127,7 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
use_master = 1;
ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_keytab, (void *) keytab,
&use_master, NULL);
@@ -139,6 +151,8 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
do any prompting or changing for keytabs, that's it. */
cleanup:
+ if (opte && krb5_gic_opt_is_shadowed(opte))
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (arg_keytab == NULL)
krb5_kt_close(context, keytab);
@@ -152,15 +166,18 @@ krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
{
krb5_error_code retval;
- krb5_get_init_creds_opt opt;
+ krb5_gic_opt_ext *opte;
char * server = NULL;
krb5_keytab keytab;
krb5_principal client_princ, server_princ;
int use_master = 0;
- krb5int_populate_gic_opt(context, &opt,
- options, addrs, ktypes,
- pre_auth_types, creds);
+ retval = krb5int_populate_gic_opt(context, &opte,
+ options, addrs, ktypes,
+ pre_auth_types, creds);
+ if (retval)
+ return retval;
+
if (arg_keytab == NULL) {
retval = krb5_kt_default(context, &keytab);
if (retval)
@@ -176,10 +193,11 @@ krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
retval = krb5_get_init_creds (context,
creds, creds->client,
krb5_prompter_posix, NULL,
- 0, server, &opt,
+ 0, server, opte,
krb5_get_as_key_keytab, (void *)keytab,
&use_master, ret_as_reply);
krb5_free_unparsed_name( context, server);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (retval) {
goto cleanup;
}
diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c
index 58d07b0..3ac7c52 100644
--- a/src/lib/krb5/krb/gic_opt.c
+++ b/src/lib/krb5/krb/gic_opt.c
@@ -63,3 +63,420 @@ krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt)
opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
opt->salt = salt;
}
+
+/*
+ * Extending the krb5_get_init_creds_opt structure. The original
+ * krb5_get_init_creds_opt structure is defined publicly. The
+ * new extended version is private. The original interface
+ * assumed a pre-allocated structure which was passed to
+ * krb5_get_init_creds_init(). The new interface assumes that
+ * the caller will call krb5_get_init_creds_alloc() and
+ * krb5_get_init_creds_free().
+ *
+ * Callers MUST NOT call krb5_get_init_creds_init() after allocating an
+ * opts structure using krb5_get_init_creds_alloc(). To do so will
+ * introduce memory leaks. Unfortunately, there is no way to enforce
+ * this behavior.
+ *
+ * Two private flags are added for backward compatibility.
+ * KRB5_GET_INIT_CREDS_OPT_EXTENDED says that the structure was allocated
+ * with the new krb5_get_init_creds_opt_alloc() function.
+ * KRB5_GET_INIT_CREDS_OPT_SHADOWED is set to indicate that the extended
+ * structure is a shadow copy of an original krb5_get_init_creds_opt
+ * structure.
+ * If KRB5_GET_INIT_CREDS_OPT_SHADOWED is set after a call to
+ * krb5int_gic_opt_to_opte(), the resulting extended structure should be
+ * freed (using krb5_get_init_creds_free). Otherwise, the original
+ * structure was already extended and there is no need to free it.
+ */
+
+/* Forward prototype */
+static void
+free_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte);
+
+static krb5_error_code
+krb5int_gic_opte_private_alloc(krb5_context context, krb5_gic_opt_ext *opte)
+{
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return EINVAL;
+
+ opte->opt_private = calloc(1, sizeof(*opte->opt_private));
+ if (NULL == opte->opt_private) {
+ return ENOMEM;
+ }
+ /* Allocate any private stuff */
+ opte->opt_private->num_preauth_data = 0;
+ opte->opt_private->preauth_data = NULL;
+ return 0;
+}
+
+static krb5_error_code
+krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
+{
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return EINVAL;
+
+ /* Free up any private stuff */
+ if (opte->opt_private->preauth_data != NULL)
+ free_gic_opt_ext_preauth_data(context, opte);
+ free(opte->opt_private);
+ opte->opt_private = NULL;
+ return 0;
+}
+
+static krb5_gic_opt_ext *
+krb5int_gic_opte_alloc(krb5_context context)
+{
+ krb5_gic_opt_ext *opte;
+ krb5_error_code code;
+
+ opte = calloc(1, sizeof(*opte));
+ if (NULL == opte)
+ return NULL;
+ opte->flags = KRB5_GET_INIT_CREDS_OPT_EXTENDED;
+
+ code = krb5int_gic_opte_private_alloc(context, opte);
+ if (code) {
+ krb5int_set_error(&context->err, code,
+ "krb5int_gic_opte_alloc: krb5int_gic_opte_private_alloc failed");
+ free(opte);
+ return NULL;
+ }
+ return(opte);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt)
+{
+ krb5_gic_opt_ext *opte;
+
+ if (NULL == opt)
+ return EINVAL;
+ *opt = NULL;
+
+ /*
+ * We return a new extended structure cast as a krb5_get_init_creds_opt
+ */
+ opte = krb5int_gic_opte_alloc(context);
+ if (NULL == opte)
+ return ENOMEM;
+
+ *opt = (krb5_get_init_creds_opt *) opte;
+ return 0;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt)
+{
+ krb5_gic_opt_ext *opte;
+
+ if (NULL == opt)
+ return;
+
+ /* Don't touch it if we didn't allocate it */
+ if (!krb5_gic_opt_is_extended(opt))
+ return;
+
+ opte = (krb5_gic_opt_ext *)opt;
+ if (opte->opt_private)
+ krb5int_gic_opte_private_free(context, opte);
+
+ free(opte);
+}
+
+static krb5_error_code
+krb5int_gic_opte_copy(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte)
+{
+ krb5_gic_opt_ext *oe;
+
+ oe = krb5int_gic_opte_alloc(context);
+ if (NULL == oe)
+ return ENOMEM;
+ memcpy(oe, opt, sizeof(*opt));
+ /* Fix these -- overwritten by the copy */
+ oe->flags |= ( KRB5_GET_INIT_CREDS_OPT_EXTENDED |
+ KRB5_GET_INIT_CREDS_OPT_SHADOWED);
+
+ *opte = oe;
+ return 0;
+}
+
+/*
+ * Convert a krb5_get_init_creds_opt pointer to a pointer to
+ * an extended, krb5_gic_opt_ext pointer. If the original
+ * pointer already points to an extended structure, then simply
+ * return the original pointer. Otherwise, if 'force' is non-zero,
+ * allocate an extended structure and copy the original over it.
+ * If the original pointer did not point to an extended structure
+ * and 'force' is zero, then return an error. This is used in
+ * cases where the original *should* be an extended structure.
+ */
+krb5_error_code
+krb5int_gic_opt_to_opte(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte,
+ unsigned int force,
+ const char *where)
+{
+ if (!krb5_gic_opt_is_extended(opt)) {
+ if (force) {
+ return krb5int_gic_opte_copy(context, opt, opte);
+ } else {
+ krb5int_set_error(&context->err, EINVAL,
+ "%s: attempt to convert non-extended krb5_get_init_creds_opt",
+ where);
+ return EINVAL;
+ }
+ }
+ /* If it is already extended, just return it */
+ *opte = (krb5_gic_opt_ext *)opt;
+ return 0;
+}
+
+static void
+free_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte)
+{
+ int i;
+
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return;
+ if (NULL == opte->opt_private || NULL == opte->opt_private->preauth_data)
+ return;
+
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ if (opte->opt_private->preauth_data[i].attr != NULL)
+ free(opte->opt_private->preauth_data[i].attr);
+ if (opte->opt_private->preauth_data[i].value != NULL)
+ free(opte->opt_private->preauth_data[i].value);
+ }
+ free(opte->opt_private->preauth_data);
+ opte->opt_private->preauth_data = NULL;
+ opte->opt_private->num_preauth_data = 0;
+}
+
+static krb5_error_code
+add_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte,
+ const char *attr,
+ const char *value)
+{
+ size_t newsize;
+ int i;
+ krb5_gic_opt_pa_data *newpad;
+
+ newsize = opte->opt_private->num_preauth_data + 1;
+ newsize = newsize * sizeof(*opte->opt_private->preauth_data);
+ if (opte->opt_private->preauth_data == NULL)
+ newpad = malloc(newsize);
+ else
+ newpad = realloc(opte->opt_private->preauth_data, newsize);
+ if (newpad == NULL)
+ return ENOMEM;
+
+ i = opte->opt_private->num_preauth_data;
+ newpad[i].attr = strdup(attr);
+ if (newpad[i].attr == NULL)
+ return ENOMEM;
+ newpad[i].value = strdup(value);
+ if (newpad[i].value == NULL) {
+ free(newpad[i].attr);
+ return ENOMEM;
+ }
+ opte->opt_private->num_preauth_data += 1;
+ opte->opt_private->preauth_data = newpad;
+ return 0;
+}
+
+/*
+ * This function allows the caller to supply options to preauth
+ * plugins. Preauth plugin modules are given a chance to look
+ * at each option at the time this function is called in ordre
+ * to check the validity of the option.
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pa(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+ krb5_error_code retval;
+ krb5_gic_opt_ext *opte;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_set_pa");
+ if (retval)
+ return retval;
+
+ /*
+ * Copy the option into the extended get_init_creds_opt structure
+ */
+ retval = add_gic_opt_ext_preauth_data(context, opte, attr, value);
+ if (retval)
+ return retval;
+
+ /*
+ * Give the plugins a chance to look at the option now.
+ */
+ retval = krb5_preauth_supply_preauth_data(context, opte, attr, value);
+ return retval;
+}
+
+/*
+ * This function allows a preauth plugin to obtain preauth
+ * options. The preauth_data returned from this function
+ * should be freed by calling krb5_get_init_creds_opt_free_pa().
+ *
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_get_pa(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ int *num_preauth_data,
+ krb5_gic_opt_pa_data **preauth_data)
+{
+ krb5_error_code retval;
+ krb5_gic_opt_ext *opte;
+ krb5_gic_opt_pa_data *p = NULL;
+ int i;
+ size_t allocsize;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_get_pa");
+ if (retval)
+ return retval;
+
+ if (num_preauth_data == NULL || preauth_data == NULL)
+ return EINVAL;
+
+ *num_preauth_data = 0;
+ *preauth_data = NULL;
+
+ if (opte->opt_private->num_preauth_data == 0)
+ return 0;
+
+ allocsize =
+ opte->opt_private->num_preauth_data * sizeof(krb5_gic_opt_pa_data);
+ p = malloc(allocsize);
+ if (p == NULL)
+ return ENOMEM;
+
+ /* Init these to make cleanup easier */
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ p[i].attr = NULL;
+ p[i].value = NULL;
+ }
+
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ p[i].attr = strdup(opte->opt_private->preauth_data[i].attr);
+ p[i].value = strdup(opte->opt_private->preauth_data[i].value);
+ if (p[i].attr == NULL || p[i].value == NULL)
+ goto cleanup;
+ }
+ *num_preauth_data = i;
+ *preauth_data = p;
+ return 0;
+cleanup:
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ if (p[i].attr != NULL)
+ free(p[i].attr);
+ if (p[i].value != NULL)
+ free(p[i].value);
+ }
+ free(p);
+ return ENOMEM;
+}
+
+/*
+ * This function frees the preauth_data that was returned by
+ * krb5_get_init_creds_opt_get_pa().
+ */
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free_pa(krb5_context context,
+ int num_preauth_data,
+ krb5_gic_opt_pa_data *preauth_data)
+{
+ int i;
+
+ if (num_preauth_data <= 0 || preauth_data == NULL)
+ return;
+
+ for (i = 0; i < num_preauth_data; i++) {
+ if (preauth_data[i].attr != NULL)
+ free(preauth_data[i].attr);
+ if (preauth_data[i].value != NULL)
+ free(preauth_data[i].value);
+ }
+ free(preauth_data);
+}
+
+
+/*
+ * This function is provided for compatibility with Heimdal's
+ * function of the same name. We ignore the principal,
+ * password, and prompter parameters.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pkinit(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_principal principal,
+ const char *x509_user_identity,
+ const char *x509_anchors,
+ char * const * x509_chain_list,
+ char * const * x509_revoke_list,
+ int flags,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ char *password)
+{
+ int i;
+ krb5_error_code retval;
+
+#define PKINIT_RSA_PROTOCOL 0x00000002 /* XXX */
+
+ if (x509_user_identity != NULL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_user_identity", x509_user_identity);
+ if (retval)
+ return retval;
+ }
+ if (x509_anchors != NULL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_anchors", x509_anchors);
+ if (retval)
+ return retval;
+ }
+ if (x509_chain_list != NULL) {
+ for (i = 0; x509_chain_list[i] != NULL; i++) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_chain_list", x509_chain_list[i]);
+ if (retval)
+ return retval;
+ }
+ }
+ if (x509_revoke_list != NULL) {
+ for (i = 0; x509_revoke_list[i] != NULL; i++) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_revoke_list", x509_revoke_list[i]);
+ if (retval)
+ return retval;
+ }
+ }
+ if (flags != 0) {
+ if (flags & PKINIT_RSA_PROTOCOL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "flag_RSA_PROTOCOL", "yes");
+ if (retval)
+ return retval;
+ }
+ }
+ return retval;
+}
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index 40288b9..5bf3000 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -85,18 +85,28 @@ krb5_get_as_key_password(
}
krb5_error_code KRB5_CALLCONV
-krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, char *password, krb5_prompter_fct prompter, void *data, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
+krb5_get_init_creds_password(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ char *password,
+ krb5_prompter_fct prompter,
+ void *data,
+ krb5_deltat start_time,
+ char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
{
krb5_error_code ret, ret2;
int use_master;
krb5_kdc_rep *as_reply;
int tries;
krb5_creds chpw_creds;
- krb5_get_init_creds_opt chpw_opts;
+ krb5_get_init_creds_opt *chpw_opts = NULL;
krb5_data pw0, pw1;
char banner[1024], pw0array[1024], pw1array[1024];
krb5_prompt prompt[2];
krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])];
+ krb5_gic_opt_ext *opte = NULL;
+ krb5_gic_opt_ext *chpw_opte = NULL;
use_master = 0;
as_reply = NULL;
@@ -119,10 +129,15 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
pw1.data[0] = '\0';
pw1.length = sizeof(pw1array);
+ ret = krb5int_gic_opt_to_opte(context, options, &opte, 1,
+ "krb5_get_init_creds_password");
+ if (ret)
+ goto cleanup;
+
/* first try: get the requested tkt from any kdc */
ret = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -151,7 +166,7 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
as_reply = NULL;
}
ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -189,15 +204,21 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
/* use a minimal set of options */
- krb5_get_init_creds_opt_init(&chpw_opts);
- krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
- krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
- krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
- krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
+ ret = krb5_get_init_creds_opt_alloc(context, &chpw_opts);
+ if (ret)
+ goto cleanup;
+ krb5_get_init_creds_opt_set_tkt_life(chpw_opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life(chpw_opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(chpw_opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(chpw_opts, 0);
+ ret = krb5int_gic_opt_to_opte(context, chpw_opts, &chpw_opte, 0,
+ "krb5_get_init_creds_password (changing password)");
+ if (ret)
+ goto cleanup;
if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
prompter, data,
- start_time, "kadmin/changepw", &chpw_opts,
+ start_time, "kadmin/changepw", chpw_opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, NULL)))
goto cleanup;
@@ -285,7 +306,7 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
is final. */
ret = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -365,6 +386,10 @@ cleanup:
}
}
+ if (chpw_opts)
+ krb5_get_init_creds_opt_free(context, chpw_opts);
+ if (opte && krb5_gic_opt_is_shadowed(opte))
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
memset(pw0array, 0, sizeof(pw0array));
memset(pw1array, 0, sizeof(pw1array));
krb5_free_cred_contents(context, &chpw_creds);
@@ -373,15 +398,20 @@ cleanup:
return(ret);
}
-void krb5int_populate_gic_opt (
- krb5_context context, krb5_get_init_creds_opt *opt,
+krb5_error_code krb5int_populate_gic_opt (
+ krb5_context context, krb5_gic_opt_ext **opte,
krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
krb5_preauthtype *pre_auth_types, krb5_creds *creds)
{
int i;
krb5_int32 starttime;
+ krb5_get_init_creds_opt *opt;
+ krb5_error_code retval;
+
+ retval = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (retval)
+ return(retval);
- krb5_get_init_creds_opt_init(opt);
if (addrs)
krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
if (ktypes) {
@@ -405,6 +435,8 @@ void krb5int_populate_gic_opt (
if (creds->times.starttime) starttime = creds->times.starttime;
krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
}
+ return krb5int_gic_opt_to_opte(context, opt, opte, 0,
+ "krb5int_populate_gic_opt");
}
/*
@@ -437,10 +469,10 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
krb5_error_code retval;
krb5_data pw0;
char pw0array[1024];
- krb5_get_init_creds_opt opt;
char * server;
krb5_principal server_princ, client_princ;
int use_master = 0;
+ krb5_gic_opt_ext *opte = NULL;
pw0array[0] = '\0';
pw0.data = pw0array;
@@ -454,21 +486,26 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
} else {
pw0.length = sizeof(pw0array);
}
- krb5int_populate_gic_opt(context, &opt,
- options, addrs, ktypes,
- pre_auth_types, creds);
- retval = krb5_unparse_name( context, creds->server, &server);
+ retval = krb5int_populate_gic_opt(context, &opte,
+ options, addrs, ktypes,
+ pre_auth_types, creds);
if (retval)
return (retval);
+ retval = krb5_unparse_name( context, creds->server, &server);
+ if (retval) {
+ return (retval);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
+ }
server_princ = creds->server;
client_princ = creds->client;
retval = krb5_get_init_creds (context,
creds, creds->client,
krb5_prompter_posix, NULL,
- 0, server, &opt,
+ 0, server, opte,
krb5_get_as_key_password, &pw0,
&use_master, ret_as_reply);
krb5_free_unparsed_name( context, server);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (retval) {
return (retval);
}
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
index 7428896..05fb08e 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -161,6 +161,10 @@ krb5_init_preauth_context(krb5_context kcontext)
context->modules[k].use_count = 0;
context->modules[k].client_process = table->process;
context->modules[k].client_tryagain = table->tryagain;
+ if (j == 0)
+ context->modules[k].client_supply_gic_opts = table->gic_opts;
+ else
+ context->modules[k].client_supply_gic_opts = NULL;
context->modules[k].request_context = NULL;
/*
* Only call request_init and request_fini once per plugin.
@@ -209,6 +213,52 @@ krb5_clear_preauth_context_use_counts(krb5_context context)
}
}
+/*
+ * Give all the preauth plugins a look at the preauth option which
+ * has just been set
+ */
+krb5_error_code
+krb5_preauth_supply_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte,
+ const char *attr,
+ const char *value)
+{
+ krb5_error_code retval;
+ int i;
+ void *pctx;
+ const char *emsg = NULL;
+
+ if (context->preauth_context == NULL)
+ krb5_init_preauth_context(context);
+ if (context->preauth_context == NULL) {
+ retval = EINVAL;
+ krb5int_set_error(&context->err, retval,
+ "krb5_preauth_supply_preauth_data: "
+ "Unable to initialize preauth context");
+ return retval;
+ }
+
+ /*
+ * Go down the list of preauth modules, and supply them with the
+ * attribute/value pair.
+ */
+ for (i = 0; i < context->preauth_context->n_modules; i++) {
+ if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
+ continue;
+ pctx = context->preauth_context->modules[i].plugin_context;
+ retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
+ (context, pctx,
+ (krb5_get_init_creds_opt *)opte, attr, value);
+ if (retval) {
+ emsg = krb5_get_error_message(context, retval);
+ krb5int_set_error(&context->err, retval, "Preauth plugin %s: %s",
+ context->preauth_context->modules[i].name, emsg);
+ break;
+ }
+ }
+ return retval;
+}
+
/* Free the per-krb5_context preauth_context. This means clearing any
* plugin-specific context which may have been created, and then
* freeing the context itself. */
@@ -403,7 +453,7 @@ client_data_proc(krb5_context kcontext,
* involved things. */
void
krb5_preauth_prepare_request(krb5_context kcontext,
- krb5_get_init_creds_opt *options,
+ krb5_gic_opt_ext *opte,
krb5_kdc_req *request)
{
int i, j;
@@ -413,7 +463,7 @@ krb5_preauth_prepare_request(krb5_context kcontext,
}
/* Add the module-specific enctype list to the request, but only if
* it's something we can safely modify. */
- if (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
+ if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
if (kcontext->preauth_context->modules[i].enctypes == NULL)
continue;
@@ -446,7 +496,8 @@ krb5_run_preauth_plugins(krb5_context kcontext,
krb5_pa_data ***out_pa_list,
int *out_pa_list_size,
int *module_ret,
- int *module_flags)
+ int *module_flags,
+ krb5_gic_opt_ext *opte)
{
int i;
krb5_pa_data *out_pa_data;
@@ -485,6 +536,7 @@ krb5_run_preauth_plugins(krb5_context kcontext,
ret = module->client_process(kcontext,
module->plugin_context,
*module->request_context_pp,
+ (krb5_get_init_creds_opt *)opte,
client_data_proc,
get_data_rock,
request,
@@ -1311,7 +1363,8 @@ krb5_do_preauth_tryagain(krb5_context kcontext,
krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock)
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte)
{
krb5_error_code ret;
krb5_pa_data *out_padata;
@@ -1342,6 +1395,7 @@ krb5_do_preauth_tryagain(krb5_context kcontext,
if ((*module->client_tryagain)(kcontext,
module->plugin_context,
*module->request_context_pp,
+ (krb5_get_init_creds_opt *)opte,
client_data_proc,
get_data_rock,
request,
@@ -1374,7 +1428,8 @@ krb5_do_preauth(krb5_context context,
krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock)
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte)
{
int h, i, j, out_pa_list_size;
int seen_etype_info2 = 0;
@@ -1567,7 +1622,8 @@ krb5_do_preauth(krb5_context context,
&out_pa_list,
&out_pa_list_size,
&module_ret,
- &module_flags);
+ &module_flags,
+ opte);
if (ret == 0) {
if (module_ret == 0) {
if (paorder[h] == PA_REAL) {
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 0393354..553dc0f 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -164,8 +164,6 @@ decode_krb5_as_rep
decode_krb5_as_req
decode_krb5_authdata
decode_krb5_authenticator
-decode_krb5_auth_pack
-decode_krb5_auth_pack_draft9
decode_krb5_cred
decode_krb5_enc_cred_part
decode_krb5_enc_data
@@ -179,20 +177,13 @@ decode_krb5_encryption_key
decode_krb5_error
decode_krb5_etype_info
decode_krb5_etype_info2
-decode_krb5_kdc_dh_key_info
decode_krb5_kdc_req_body
decode_krb5_pa_enc_ts
-decode_krb5_pa_pk_as_rep
-decode_krb5_pa_pk_as_req
-decode_krb5_pa_pk_as_req_draft9
decode_krb5_padata_sequence
decode_krb5_predicted_sam_response
-decode_krb5_principal_name
decode_krb5_priv
decode_krb5_pwd_data
decode_krb5_pwd_sequence
-decode_krb5_reply_key_pack
-decode_krb5_reply_key_pack_draft9
decode_krb5_safe
decode_krb5_safe_with_body
decode_krb5_sam_challenge
@@ -203,9 +194,6 @@ decode_krb5_sam_response_2
decode_krb5_tgs_rep
decode_krb5_tgs_req
decode_krb5_ticket
-decode_krb5_td_dh_parameters
-decode_krb5_td_trusted_certifiers
-decode_krb5_typed_data
encode_krb5_alt_method
encode_krb5_ap_rep
encode_krb5_ap_rep_enc_part
@@ -214,8 +202,6 @@ encode_krb5_as_rep
encode_krb5_as_req
encode_krb5_authdata
encode_krb5_authenticator
-encode_krb5_auth_pack
-encode_krb5_auth_pack_draft9
encode_krb5_cred
encode_krb5_enc_cred_part
encode_krb5_enc_data
@@ -228,20 +214,13 @@ encode_krb5_encryption_key
encode_krb5_error
encode_krb5_etype_info
encode_krb5_etype_info2
-encode_krb5_kdc_dh_key_info
encode_krb5_kdc_req_body
encode_krb5_pa_enc_ts
-encode_krb5_pa_pk_as_rep
-encode_krb5_pa_pk_as_rep_draft9
-encode_krb5_pa_pk_as_req
-encode_krb5_pa_pk_as_req_draft9
encode_krb5_padata_sequence
encode_krb5_predicted_sam_response
encode_krb5_priv
encode_krb5_pwd_data
encode_krb5_pwd_sequence
-encode_krb5_reply_key_pack
-encode_krb5_reply_key_pack_draft9
encode_krb5_safe
encode_krb5_safe_with_body
encode_krb5_sam_challenge
@@ -251,12 +230,9 @@ encode_krb5_sam_key
encode_krb5_sam_response
encode_krb5_sam_response_2
encode_krb5_setpw_req
-encode_krb5_td_dh_parameters
-encode_krb5_td_trusted_certifiers
encode_krb5_tgs_rep
encode_krb5_tgs_req
encode_krb5_ticket
-encode_krb5_typed_data
et_asn1_error_table
et_k524_error_table
et_kdb5_error_table
@@ -460,10 +436,15 @@ krb5_get_in_tkt_with_password
krb5_get_in_tkt_with_skey
krb5_get_init_creds
krb5_get_init_creds_keytab
+krb5_get_init_creds_opt_alloc
+krb5_get_init_creds_opt_free
+krb5_get_init_creds_opt_free_pa
+krb5_get_init_creds_opt_get_pa
krb5_get_init_creds_opt_init
krb5_get_init_creds_opt_set_address_list
krb5_get_init_creds_opt_set_etype_list
krb5_get_init_creds_opt_set_forwardable
+krb5_get_init_creds_opt_set_pa
krb5_get_init_creds_opt_set_preauth_list
krb5_get_init_creds_opt_set_proxiable
krb5_get_init_creds_opt_set_renew_life
@@ -761,3 +742,4 @@ krb5_get_error_message
krb5_free_error_message
krb5_clear_error_message
krb5int_init_context_kdc
+krb5_get_init_creds_opt_set_pkinit
diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c
index cd7d0c3..ba87ad7 100644
--- a/src/lib/krb5/os/accessor.c
+++ b/src/lib/krb5/os/accessor.c
@@ -77,6 +77,30 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version)
S (krb5_ser_unpack_int64, krb5_ser_unpack_int64),
S (asn1_ldap_encode_sequence_of_keys, krb5int_ldap_encode_sequence_of_keys),
S (asn1_ldap_decode_sequence_of_keys, krb5int_ldap_decode_sequence_of_keys),
+ S (encode_krb5_pa_pk_as_req, encode_krb5_pa_pk_as_req),
+ S (encode_krb5_pa_pk_as_req_draft9, encode_krb5_pa_pk_as_req_draft9), S (encode_krb5_pa_pk_as_rep, encode_krb5_pa_pk_as_rep),
+ S (encode_krb5_pa_pk_as_rep_draft9, encode_krb5_pa_pk_as_rep_draft9),
+ S (encode_krb5_auth_pack, encode_krb5_auth_pack),
+ S (encode_krb5_auth_pack_draft9, encode_krb5_auth_pack_draft9),
+ S (encode_krb5_kdc_dh_key_info, encode_krb5_kdc_dh_key_info),
+ S (encode_krb5_reply_key_pack, encode_krb5_reply_key_pack),
+ S (encode_krb5_reply_key_pack_draft9, encode_krb5_reply_key_pack_draft9),
+ S (encode_krb5_typed_data, encode_krb5_typed_data),
+ S (encode_krb5_td_trusted_certifiers, encode_krb5_td_trusted_certifiers),
+ S (encode_krb5_td_dh_parameters, encode_krb5_td_dh_parameters),
+ S (decode_krb5_pa_pk_as_req, decode_krb5_pa_pk_as_req),
+ S (decode_krb5_pa_pk_as_req_draft9, decode_krb5_pa_pk_as_req_draft9),
+ S (decode_krb5_pa_pk_as_rep, decode_krb5_pa_pk_as_rep),
+ S (decode_krb5_pa_pk_as_rep_draft9, decode_krb5_pa_pk_as_rep_draft9),
+ S (decode_krb5_auth_pack, decode_krb5_auth_pack),
+ S (decode_krb5_auth_pack_draft9, decode_krb5_auth_pack_draft9),
+ S (decode_krb5_kdc_dh_key_info, decode_krb5_kdc_dh_key_info),
+ S (decode_krb5_principal_name, decode_krb5_principal_name),
+ S (decode_krb5_reply_key_pack, decode_krb5_reply_key_pack),
+ S (decode_krb5_reply_key_pack_draft9, decode_krb5_reply_key_pack_draft9),
+ S (decode_krb5_typed_data, decode_krb5_typed_data),
+ S (decode_krb5_td_trusted_certifiers, decode_krb5_td_trusted_certifiers),
+ S (decode_krb5_td_dh_parameters, decode_krb5_td_dh_parameters),
#if DESIGNATED_INITIALIZERS
};
#else
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index 6a9060b..d347835 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -155,7 +155,12 @@ krb5_c_string_to_key_with_params
krb5_get_in_tkt_with_password ; DEPRECATED
krb5_get_in_tkt_with_skey ; DEPRECATED
krb5_get_init_creds_keytab
+ krb5_get_init_creds_opt_alloc
+ krb5_get_init_creds_opt_free
+ krb5_get_init_creds_opt_free_pa
+ krb5_get_init_creds_opt_get_pa
krb5_get_init_creds_opt_init
+ krb5_get_init_creds_opt_set_pa
krb5_get_init_creds_opt_set_address_list
krb5_get_init_creds_opt_set_etype_list
krb5_get_init_creds_opt_set_forwardable
diff --git a/src/plugins/preauth/cksum_body/cksum_body_main.c b/src/plugins/preauth/cksum_body/cksum_body_main.c
index 6b46b00..59bf525 100644
--- a/src/plugins/preauth/cksum_body/cksum_body_main.c
+++ b/src/plugins/preauth/cksum_body/cksum_body_main.c
@@ -68,6 +68,11 @@ struct server_stats{
int successes, failures;
};
+typedef struct _test_svr_req_ctx {
+ int value1;
+ int value2;
+} test_svr_req_ctx;
+
static int
client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
{
@@ -78,6 +83,7 @@ static krb5_error_code
client_process(krb5_context kcontext,
void *client_plugin_context,
void *client_request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc client_get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -99,6 +105,27 @@ client_process(krb5_context kcontext,
krb5_error_code status = 0;
krb5_int32 cksumtype, *enctypes;
unsigned int i, n_enctypes, cksumtype_count;
+ int num_gic_info = 0;
+ krb5_gic_opt_pa_data *gic_info;
+
+ status = krb5_get_init_creds_opt_get_pa(kcontext, opt,
+ &num_gic_info, &gic_info);
+ if (status && status != ENOENT) {
+#ifdef DEBUG
+ fprintf(stderr, "Error from krb5_get_init_creds_opt_get_pa: %s\n",
+ error_message(status));
+#endif
+ return status;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "(cksum_body) Got the following gic options:\n");
+#endif
+ for (i = 0; i < num_gic_info; i++) {
+#ifdef DEBUG
+ fprintf(stderr, " '%s' = '%s'\n", gic_info[i].attr, gic_info[i].value);
+#endif
+ }
+ krb5_get_init_creds_opt_free_pa(kcontext, num_gic_info, gic_info);
memset(&checksum, 0, sizeof(checksum));
@@ -193,6 +220,20 @@ client_process(krb5_context kcontext,
return 0;
}
+static krb5_error_code
+client_gic_opt(krb5_context kcontext,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+#ifdef DEBUG
+ fprintf(stderr, "(cksum_body) client_gic_opt: received '%s' = '%s'\n",
+ attr, value);
+#endif
+ return 0;
+}
+
/* Initialize and tear down the server-side module, and do stat tracking. */
static krb5_error_code
server_init(krb5_context kcontext, void **module_context)
@@ -200,7 +241,7 @@ server_init(krb5_context kcontext, void **module_context)
struct server_stats *stats;
stats = malloc(sizeof(struct server_stats));
if (stats == NULL)
- return ENOMEM;
+ return ENOMEM;
stats->successes = 0;
stats->failures = 0;
*module_context = stats;
@@ -304,6 +345,7 @@ server_verify(krb5_context kcontext,
krb5_error_code status;
struct server_stats *stats;
krb5_data *test_edata;
+ test_svr_req_ctx *svr_req_ctx;
stats = pa_module_context;
@@ -456,6 +498,18 @@ server_verify(krb5_context kcontext,
}
}
+ /* Return a request context to exercise code that handles it */
+ svr_req_ctx = malloc(sizeof(*svr_req_ctx));
+ if (svr_req_ctx != NULL) {
+ svr_req_ctx->value1 = 111111;
+ svr_req_ctx->value2 = 222222;
+#ifdef DEBUG
+ fprintf(stderr, "server_verify: returning context at %p\n",
+ svr_req_ctx);
+#endif
+ }
+ *pa_request_context = svr_req_ctx;
+
/* Note that preauthentication succeeded. */
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
stats->successes++;
@@ -482,6 +536,37 @@ server_return(krb5_context kcontext,
return 0;
}
+/* Test server request context freeing */
+static krb5_error_code
+server_free_reqctx(krb5_context kcontext,
+ void *pa_module_context,
+ void **pa_request_context)
+{
+ test_svr_req_ctx *svr_req_ctx;
+#ifdef DEBUG
+ fprintf(stderr, "server_free_reqctx: entered!\n");
+#endif
+ if (pa_request_context == NULL)
+ return 0;
+
+ svr_req_ctx = *pa_request_context;
+ if (svr_req_ctx == NULL)
+ return 0;
+
+ if (svr_req_ctx->value1 != 111111 || svr_req_ctx->value2 != 222222) {
+ fprintf(stderr, "server_free_reqctx: got invalid req context "
+ "at %p with values %d and %d\n",
+ svr_req_ctx, svr_req_ctx->value1, svr_req_ctx->value2);
+ return EINVAL;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "server_free_reqctx: freeing context at %p\n", svr_req_ctx);
+#endif
+ free(svr_req_ctx);
+ *pa_request_context = NULL;
+ return 0;
+}
+
static int
server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
{
@@ -506,6 +591,7 @@ struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
NULL, /* request fini function */
client_process, /* process function */
NULL, /* try_again function */
+ client_gic_opt /* get init creds opt function */
};
struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {
@@ -517,5 +603,5 @@ struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {
server_get_edata,
server_verify,
server_return,
- NULL
+ server_free_reqctx
};
diff --git a/src/plugins/preauth/pkinit/Makefile.in b/src/plugins/preauth/pkinit/Makefile.in
index 1bfdddc..30ab4d0 100644
--- a/src/plugins/preauth/pkinit/Makefile.in
+++ b/src/plugins/preauth/pkinit/Makefile.in
@@ -27,12 +27,14 @@ SHLIB_DIRS=-L$(TOPLIBD)
SHLIB_RDIRS=$(KRB5_LIBDIR)
SRCS= \
+ $(srcdir)/pkinit_accessor.c \
$(srcdir)/pkinit_srv.c \
$(srcdir)/pkinit_lib.c \
$(srcdir)/pkinit_clnt.c
STOBJLISTS=OBJS.ST
STLIBOBJS= \
+ pkinit_accessor.o \
pkinit_srv.o \
pkinit_lib.o \
pkinit_clnt.o
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index 89a86e9..cea8efb 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -31,6 +31,11 @@
#ifndef _PKINIT_H
#define _PKINIT_H
+#include "pkinit_accessor.h"
+
+#define DH_PROTOCOL 1
+#define RSA_PROTOCOL 2
+
extern const krb5_octet_data dh_oid;
extern unsigned char pkinit_1024_dhprime[1024/8];
extern unsigned char pkinit_2048_dhprime[2048/8];
@@ -38,9 +43,11 @@ extern unsigned char pkinit_4096_dhprime[4096/8];
typedef struct _pkinit_context {
int magic;
+ krb5_context context;
int require_eku;
int require_san;
int allow_upn;
+ int dh_or_rsa;
int require_crl_checking;
char *ctx_identity;
char *ctx_anchors;
@@ -68,20 +75,47 @@ typedef struct _pkinit_context {
typedef struct _pkinit_req_context {
int magic;
+ pkinit_context *plugctx;
DH *dh;
int dh_size;
int require_eku;
int require_san;
int require_hostname_match;
int allow_upn;
+ int dh_or_rsa;
int require_crl_checking;
int win2k_target;
int win2k_require_cksum;
krb5_preauthtype patype;
+ krb5_prompter_fct prompter;
+ void *prompter_data;
+ int pkcs11_method;
+#ifndef WITHOUT_PKCS11
+ char *p11_module_name;
+ void *p11_module;
+ unsigned int slotid;
+ CK_SESSION_HANDLE session;
+ CK_FUNCTION_LIST_PTR p11;
+ CK_BYTE_PTR cert_id;
+ int cert_id_len;
+ CK_MECHANISM_TYPE mech;
+#endif
+ void *credctx;
} pkinit_req_context;
-/* Function prototypes */
+typedef struct _pkinit_cred_context {
+ STACK_OF(X509) *cert;
+ STACK_OF(X509) *trustedCAs;
+ STACK_OF(X509) *untrustedCAs;
+ DH *dh;
+} pkinit_cred_context;
+
+int pkinit_get_certs(int type, STACK_OF(X509) **certs);
+int get_file_certs(char *name, STACK_OF(X509) **certs);
+int get_dir_certs(char *name, STACK_OF(X509) **certs);
+int get_pkcs11_certs(char *name, STACK_OF(X509) **certs);
+/* Function prototypes */
void openssl_init(void);
krb5_error_code pkinit_init_dh_params(krb5_context, pkinit_context *);
@@ -94,14 +128,14 @@ int pkinit_check_dh_params
(BIGNUM * p1, BIGNUM * p2, BIGNUM * g1, BIGNUM * q1);
krb5_error_code pkinit_sign_data
- (unsigned char *data, int data_len, unsigned char **sig,
- int *sig_len, char *filename);
+ (pkinit_req_context *, unsigned char *data, int data_len,
+ unsigned char **sig, int *sig_len, char *filename);
krb5_error_code create_signature
(unsigned char **, int *, unsigned char *, int, char *);
krb5_error_code pkinit_decode_data
- (unsigned char *data, int data_len, unsigned char **decoded,
+ (pkinit_req_context *, unsigned char *data, int data_len, unsigned char **decoded,
int *decoded_len, char *filename, X509 *cert);
krb5_error_code decode_data
@@ -109,7 +143,7 @@ krb5_error_code decode_data
krb5_error_code pkcs7_signeddata_create
(unsigned char *, int, unsigned char **, int *, X509 *,
- char *, ASN1_OBJECT *, krb5_context);
+ char *, ASN1_OBJECT *, krb5_context, pkinit_req_context *);
krb5_error_code pkcs7_signeddata_verify
(unsigned char *, int, char **, int *, X509 **,
@@ -127,7 +161,7 @@ krb5_error_code pkcs7_envelopeddata_create
krb5_error_code pkcs7_envelopeddata_verify
(unsigned char *, int, char **, int *, X509 *, char *,
- krb5_preauthtype , pkinit_context *, X509 **, krb5_context);
+ krb5_preauthtype, X509 **, pkinit_req_context *);
int verify_id_pkinit_san
(X509 * x, krb5_principal *out, krb5_context context,
diff --git a/src/plugins/preauth/pkinit/pkinit_accessor.c b/src/plugins/preauth/pkinit/pkinit_accessor.c
new file mode 100644
index 0000000..bdd7810
--- /dev/null
+++ b/src/plugins/preauth/pkinit/pkinit_accessor.c
@@ -0,0 +1,100 @@
+/*
+ * COPYRIGHT (C) 2006
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of The University of
+ * Michigan is not used in any advertising or publicity
+ * pertaining to the use of distribution of this software
+ * without specific, written prior authorization. If the
+ * above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+#include <k5-int.h>
+
+#define DEF_FUNC_PTRS(type) \
+krb5_error_code (*k5int_encode_##type)(const type *, krb5_data **); \
+krb5_error_code (*k5int_decode_##type)(const krb5_data *, type **)
+
+#define DEF_FUNC_PTRS_ARRAY(type) \
+krb5_error_code (*k5int_encode_##type)(const type **, krb5_data **); \
+krb5_error_code (*k5int_decode_##type)(const krb5_data *, type ***)
+
+DEF_FUNC_PTRS(krb5_auth_pack);
+DEF_FUNC_PTRS(krb5_auth_pack_draft9);
+DEF_FUNC_PTRS(krb5_kdc_dh_key_info);
+DEF_FUNC_PTRS(krb5_pa_pk_as_rep);
+DEF_FUNC_PTRS(krb5_pa_pk_as_rep_draft9);
+DEF_FUNC_PTRS(krb5_pa_pk_as_req);
+DEF_FUNC_PTRS(krb5_pa_pk_as_req_draft9);
+DEF_FUNC_PTRS(krb5_reply_key_pack);
+DEF_FUNC_PTRS(krb5_reply_key_pack_draft9);
+DEF_FUNC_PTRS_ARRAY(krb5_typed_data);
+
+/* special cases... */
+krb5_error_code (*k5int_decode_krb5_principal_name)
+ (const krb5_data *, krb5_principal_data **);
+
+krb5_error_code (*k5int_encode_krb5_td_dh_parameters)
+ (const krb5_algorithm_identifier **, krb5_data **code);
+krb5_error_code (*k5int_decode_krb5_td_dh_parameters)
+ (const krb5_data *, krb5_algorithm_identifier ***);
+
+krb5_error_code (*k5int_encode_krb5_td_trusted_certifiers)
+ (const krb5_external_principal_identifier **, krb5_data **code);
+krb5_error_code (*k5int_decode_krb5_td_trusted_certifiers)
+ (const krb5_data *, krb5_external_principal_identifier ***);
+
+
+
+/*
+ * Grab internal function pointers from the krb5int_accessor
+ * structure and make them available
+ */
+krb5_error_code pkinit_accessor_init()
+{
+ krb5_error_code retval;
+ krb5int_access k5int;
+
+ retval = krb5int_accessor(&k5int, KRB5INT_ACCESS_VERSION);
+ if (retval)
+ return retval;
+#define SET_PTRS(type) \
+k5int_encode_##type = k5int.encode_##type; \
+k5int_decode_##type = k5int.decode_##type;
+
+ SET_PTRS(krb5_auth_pack);
+ SET_PTRS(krb5_auth_pack_draft9);
+ SET_PTRS(krb5_kdc_dh_key_info);
+ SET_PTRS(krb5_pa_pk_as_rep);
+ SET_PTRS(krb5_pa_pk_as_rep_draft9);
+ SET_PTRS(krb5_pa_pk_as_req);
+ SET_PTRS(krb5_pa_pk_as_req_draft9);
+ SET_PTRS(krb5_reply_key_pack);
+ SET_PTRS(krb5_reply_key_pack_draft9);
+ SET_PTRS(krb5_td_dh_parameters);
+ SET_PTRS(krb5_td_trusted_certifiers);
+ SET_PTRS(krb5_typed_data);
+
+ /* special cases... */
+ k5int_decode_krb5_principal_name = k5int.decode_krb5_principal_name;
+ return 0;
+}
diff --git a/src/plugins/preauth/pkinit/pkinit_accessor.h b/src/plugins/preauth/pkinit/pkinit_accessor.h
new file mode 100644
index 0000000..1e1cf2e
--- /dev/null
+++ b/src/plugins/preauth/pkinit/pkinit_accessor.h
@@ -0,0 +1,67 @@
+/*
+ * COPYRIGHT (C) 2006
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of The University of
+ * Michigan is not used in any advertising or publicity
+ * pertaining to the use of distribution of this software
+ * without specific, written prior authorization. If the
+ * above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+#ifndef _PKINIT_ACCESSOR_H
+#define _PKINIT_ACCESSOR_H
+
+#define DEF_EXT_FUNC_PTRS(type) \
+extern krb5_error_code (*k5int_encode_##type)(const type *, krb5_data **); \
+extern krb5_error_code (*k5int_decode_##type)(const krb5_data *, type **)
+
+#define DEF_EXT_FUNC_PTRS_ARRAY(type) \
+extern krb5_error_code (*k5int_encode_##type)(const type **, krb5_data **); \
+extern krb5_error_code (*k5int_decode_##type)(const krb5_data *, type ***)
+
+DEF_EXT_FUNC_PTRS(krb5_auth_pack);
+DEF_EXT_FUNC_PTRS(krb5_auth_pack_draft9);
+DEF_EXT_FUNC_PTRS(krb5_kdc_dh_key_info);
+DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_rep);
+DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_rep_draft9);
+DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_req);
+DEF_EXT_FUNC_PTRS(krb5_pa_pk_as_req_draft9);
+DEF_EXT_FUNC_PTRS(krb5_reply_key_pack);
+DEF_EXT_FUNC_PTRS(krb5_reply_key_pack_draft9);
+DEF_EXT_FUNC_PTRS_ARRAY(krb5_typed_data);
+
+/* special cases... */
+extern krb5_error_code (*k5int_decode_krb5_principal_name)
+ (const krb5_data *, krb5_principal_data **);
+
+extern krb5_error_code (*k5int_encode_krb5_td_dh_parameters)
+ (const krb5_algorithm_identifier **, krb5_data **code);
+extern krb5_error_code (*k5int_decode_krb5_td_dh_parameters)
+ (const krb5_data *, krb5_algorithm_identifier ***);
+
+extern krb5_error_code (*k5int_encode_krb5_td_trusted_certifiers)
+ (const krb5_external_principal_identifier **, krb5_data **code);
+extern krb5_error_code (*k5int_decode_krb5_td_trusted_certifiers)
+ (const krb5_data *, krb5_external_principal_identifier ***);
+
+#endif /* _PKINIT_ACCESSOR_H */
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index 77ea3b7..b3233b1 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -35,6 +35,7 @@
#include <ctype.h>
#include <assert.h>
#include <dlfcn.h>
+#include <sys/stat.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -63,15 +64,12 @@
#define pkiDebug(args...)
#endif
-#define MAX_CERT_SIZE 4096
-#define MAX_ID_SIZE 4
-#define MAX_N_OBJS 6
-
-#define DH_PROTOCOL 0
-#define RSA_PROTOCOL 1
+#define PKCS11_MODNAME "opensc-pkcs11.so"
+#define PK_SIGLEN_GUESS 1000
krb5_error_code pkinit_client_process
(krb5_context context, void *plugin_context, void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req * request, krb5_data *encoded_request_body,
@@ -83,6 +81,7 @@ krb5_error_code pkinit_client_process
krb5_error_code pkinit_client_tryagain
(krb5_context context, void *plugin_context, void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req * request, krb5_data *encoded_request_body,
@@ -120,10 +119,11 @@ krb5_error_code pa_pkinit_parse_rep
krb5_pa_data * in_padata, krb5_pa_data ** out_padata,
krb5_enctype etype, krb5_keyblock * as_key, krb5_data *);
-static int using_pkcs11(void);
+krb5_error_code pkinit_find_private_key
+ (pkinit_req_context *, CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp);
krb5_error_code pkinit_get_client_cert
- (const char *principal, char *filename, X509 ** client_cert);
+ (pkinit_req_context *, const char *, char *, X509 **);
krb5_error_code create_issuerAndSerial
(X509 *cert, unsigned char **out, int *out_len);
@@ -144,10 +144,8 @@ static krb5_error_code create_krb5_trustedCas
(STACK_OF(X509) *, int flag, krb5_trusted_ca ***);
#ifndef WITHOUT_PKCS11
-static krb5_error_code pkinit_open_session
- (krb5_context, krb5_prompter_fct, void *);
-
-static void pkinit_close_session(void);
+static krb5_error_code pkinit_login(pkinit_req_context *reqctx, CK_TOKEN_INFO *tip);
+static krb5_error_code pkinit_open_session(pkinit_req_context *);
#endif
static void init_krb5_subject_pk_info(krb5_subject_pk_info **in);
@@ -188,6 +186,8 @@ pa_pkinit_gen_req(krb5_context context,
pkiDebug("pa_pkinit_gen_req: enctype = %d\n", *etype);
cksum.contents = NULL;
reqctx->patype = in_padata->pa_type;
+ reqctx->prompter = prompter;
+ reqctx->prompter_data = prompter_data;
/* If we don't have a client cert, we're done */
if (request->client == NULL) {
@@ -198,21 +198,14 @@ pa_pkinit_gen_req(krb5_context context,
if (retval)
goto cleanup;
- if (using_pkcs11()) {
-#ifndef WITHOUT_PKCS11
- if (pkinit_open_session(context, prompter, prompter_data)) {
- pkiDebug("can't open pkcs11 session\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
-#endif
- } else {
+ if (!reqctx->pkcs11_method) {
if (get_filename(&filename, "X509_USER_CERT", 0) != 0) {
pkiDebug("failed to get user's cert\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
}
- retval = pkinit_get_client_cert(client_principal, filename, &client_cert);
+ retval = pkinit_get_client_cert(reqctx, client_principal, filename, &client_cert);
if (filename != NULL)
free(filename);
free(client_principal);
@@ -243,6 +236,10 @@ pa_pkinit_gen_req(krb5_context context,
der_req, &cksum);
if (retval)
goto cleanup;
+#ifdef DEBUG_CKSUM
+ pkiDebug("calculating checksum on buf size (%d)\n", der_req->length);
+ print_buffer(der_req->data, der_req->length);
+#endif
retval = krb5_us_timeofday(context, &ctsec, &cusec);
if (retval)
@@ -331,7 +328,7 @@ pkinit_as_req_create(krb5_context context,
krb5_pa_pk_as_req *req = NULL;
krb5_auth_pack_draft9 *auth_pack9 = NULL;
krb5_pa_pk_as_req_draft9 *req9 = NULL;
- int protocol = DH_PROTOCOL;
+ int protocol = reqctx->dh_or_rsa;
char *filename = NULL;
#ifdef KDC_CERT
X509 *kdc_cert = NULL;
@@ -415,10 +412,10 @@ pkinit_as_req_create(krb5_context context,
/* Encode the authpack */
switch((int)pa_type) {
case KRB5_PADATA_PK_AS_REQ:
- retval = encode_krb5_auth_pack(auth_pack, &coded_auth_pack);
+ retval = k5int_encode_krb5_auth_pack(auth_pack, &coded_auth_pack);
break;
case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = encode_krb5_auth_pack_draft9(auth_pack9, &coded_auth_pack);
+ retval = k5int_encode_krb5_auth_pack_draft9(auth_pack9, &coded_auth_pack);
break;
}
if (retval) {
@@ -429,7 +426,7 @@ pkinit_as_req_create(krb5_context context,
print_buffer_bin(coded_auth_pack->data, coded_auth_pack->length, "/tmp/client_auth_pack");
#endif
- if (!using_pkcs11() && get_filename(&filename, "X509_USER_KEY", 0) != 0) {
+ if (!reqctx->pkcs11_method && get_filename(&filename, "X509_USER_KEY", 0) != 0) {
pkiDebug("failed to get user key filename\n");
retval = -1;
goto cleanup;
@@ -446,7 +443,7 @@ pkinit_as_req_create(krb5_context context,
retval = pkcs7_signeddata_create(coded_auth_pack->data,
coded_auth_pack->length, &req->signedAuthPack.data,
&req->signedAuthPack.length, cert, filename,
- plgctx->id_pkinit_authData, context);
+ plgctx->id_pkinit_authData, context, reqctx);
break;
case KRB5_PADATA_PK_AS_REQ_OLD:
init_krb5_pa_pk_as_req_draft9(&req9);
@@ -457,7 +454,7 @@ pkinit_as_req_create(krb5_context context,
retval = pkcs7_signeddata_create(coded_auth_pack->data,
coded_auth_pack->length, &req9->signedAuthPack.data,
&req9->signedAuthPack.length, cert, filename,
- plgctx->id_pkinit_authData9, context);
+ plgctx->id_pkinit_authData9, context, reqctx);
break;
}
krb5_free_data(context, coded_auth_pack);
@@ -491,7 +488,7 @@ pkinit_as_req_create(krb5_context context,
goto cleanup;
#endif
/* Encode the as-req */
- retval = encode_krb5_pa_pk_as_req(req, as_req);
+ retval = k5int_encode_krb5_pa_pk_as_req(req, as_req);
break;
case KRB5_PADATA_PK_AS_REQ_OLD:
if (trusted_CAs) {
@@ -506,11 +503,12 @@ pkinit_as_req_create(krb5_context context,
goto cleanup;
#endif
/* Encode the as-req */
- retval = encode_krb5_pa_pk_as_req_draft9(req9, as_req);
+ retval = k5int_encode_krb5_pa_pk_as_req_draft9(req9, as_req);
break;
}
#ifdef DEBUG_ASN1
- print_buffer_bin((*as_req)->data, (*as_req)->length, "/tmp/client_as_req");
+ if (!retval)
+ print_buffer_bin((*as_req)->data, (*as_req)->length, "/tmp/client_as_req");
#endif
cleanup:
@@ -649,12 +647,12 @@ pa_pkinit_parse_rep(krb5_context context,
if (retval)
return retval;
- if (!using_pkcs11() && get_filename(&filename, "X509_USER_CERT", 0) != 0) {
+ if (!reqctx->pkcs11_method && get_filename(&filename, "X509_USER_CERT", 0) != 0) {
pkiDebug("failed to get user's cert\n");
retval = -1;
goto cleanup;
}
- retval = pkinit_get_client_cert(princ_name, filename, &client_cert);
+ retval = pkinit_get_client_cert(reqctx, princ_name, filename, &client_cert);
if (filename != NULL)
free(filename);
if (retval) {
@@ -714,7 +712,6 @@ pkinit_as_rep_parse(krb5_context context,
long der_len = 0;
char *filename = NULL;
krb5_checksum cksum = {0, 0, 0, NULL};
- int i = 0;
krb5_principal tmp_server;
assert((as_rep != NULL) && (key_block != NULL));
@@ -723,7 +720,7 @@ pkinit_as_rep_parse(krb5_context context,
print_buffer_bin(as_rep->data, as_rep->length, "/tmp/client_as_rep");
#endif
- if ((retval = decode_krb5_pa_pk_as_rep(as_rep, &kdc_reply))) {
+ if ((retval = k5int_decode_krb5_pa_pk_as_rep(as_rep, &kdc_reply))) {
pkiDebug("decode_krb5_as_rep failed %d\n", retval);
return retval;
}
@@ -731,6 +728,9 @@ pkinit_as_rep_parse(krb5_context context,
switch(kdc_reply->choice) {
case choice_pa_pk_as_rep_dhInfo:
pkiDebug("as_rep: DH key transport algorithm\n");
+#ifdef DEBUG_ASN1
+ print_buffer_bin(kdc_reply->u.dh_Info.dhSignedData.data, kdc_reply->u.dh_Info.dhSignedData.length, "/tmp/client_kdc_signeddata");
+#endif
if ((retval = pkcs7_signeddata_verify(
kdc_reply->u.dh_Info.dhSignedData.data,
kdc_reply->u.dh_Info.dhSignedData.length,
@@ -743,7 +743,7 @@ pkinit_as_rep_parse(krb5_context context,
break;
case choice_pa_pk_as_rep_encKeyPack:
pkiDebug("as_rep: RSA key transport algorithm\n");
- if (!using_pkcs11() && get_filename(&filename, "X509_USER_KEY", 0) != 0) {
+ if (!reqctx->pkcs11_method && get_filename(&filename, "X509_USER_KEY", 0) != 0) {
pkiDebug("failed to get client's key filename\n");
goto cleanup;
}
@@ -751,7 +751,7 @@ pkinit_as_rep_parse(krb5_context context,
kdc_reply->u.encKeyPack.data,
kdc_reply->u.encKeyPack.length,
&dh_data.data, &dh_data.length, client_cert, filename,
- pa_type, plgctx, &kdc_cert, context)) != 0) {
+ pa_type, &kdc_cert, reqctx)) != 0) {
pkiDebug("failed to verify pkcs7 enveloped data\n");
goto cleanup;
}
@@ -806,7 +806,7 @@ pkinit_as_rep_parse(krb5_context context,
#ifdef DEBUG_ASN1
print_buffer_bin(dh_data.data, dh_data.length, "/tmp/client_dh_key");
#endif
- if ((retval = decode_krb5_kdc_dh_key_info(&dh_data,
+ if ((retval = k5int_decode_krb5_kdc_dh_key_info(&dh_data,
&kdc_dh)) != 0) {
pkiDebug("failed to decode kdc_dh_key_info\n");
goto cleanup;
@@ -841,14 +841,14 @@ pkinit_as_rep_parse(krb5_context context,
#ifdef DEBUG_ASN1
print_buffer_bin(dh_data.data, dh_data.length, "/tmp/client_key_pack");
#endif
- if ((retval = decode_krb5_reply_key_pack(&dh_data,
+ if ((retval = k5int_decode_krb5_reply_key_pack(&dh_data,
&key_pack)) != 0) {
pkiDebug("failed to decode reply_key_pack\n");
if (pa_type == KRB5_PADATA_PK_AS_REP)
goto cleanup;
else {
if ((retval =
- decode_krb5_reply_key_pack_draft9(&dh_data,
+ k5int_decode_krb5_reply_key_pack_draft9(&dh_data,
&key_pack9)) != 0) {
pkiDebug("failed to decode reply_key_pack_draft9\n");
goto cleanup;
@@ -887,10 +887,10 @@ pkinit_as_rep_parse(krb5_context context,
print_buffer(encoded_request->data, encoded_request->length);
pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
print_buffer(key_pack->replyKey.contents, key_pack->replyKey.length);
- pkiDebug("received checksum type=%d size=%d ", key_pack->asChecksum.checksum_type, key_pack->asChecksum.length);
- print_buffer(key_pack->asChecksum.contents, key_pack->asChecksum.length);
- pkiDebug("expected checksum type=%d size=%d ", cksum.checksum_type, cksum.length);
- print_buffer(cksum.contents, cksum.length);
+ pkiDebug("received checksum type=%d size=%d ", key_pack->asChecksum.checksum_type, key_pack->asChecksum.length);
+ print_buffer(key_pack->asChecksum.contents, key_pack->asChecksum.length);
+ pkiDebug("expected checksum type=%d size=%d ", cksum.checksum_type, cksum.length);
+ print_buffer(cksum.contents, cksum.length);
#endif
goto cleanup;
} else
@@ -982,6 +982,7 @@ krb5_error_code
pkinit_client_process(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -1068,7 +1069,7 @@ pkinit_decode_td_dh_params(krb5_data *data,
krb5_algorithm_identifier **algId = NULL;
int i = 0, ok = 0, free_dh = 1;
- retval = decode_krb5_td_dh_parameters(data, &algId);
+ retval = k5int_decode_krb5_td_dh_parameters(data, &algId);
if (retval) {
pkiDebug("decode_krb5_td_dh_parameters failed\n");
goto cleanup;
@@ -1076,7 +1077,7 @@ pkinit_decode_td_dh_params(krb5_data *data,
while (algId[i] != NULL) {
DH *dh = NULL;
unsigned char *tmp = NULL;
- int dh_prime_bits = 0, dh_err = 0;
+ int dh_prime_bits = 0;
if (algId[i]->algorithm.length != dh_oid.length ||
memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
@@ -1143,6 +1144,7 @@ krb5_error_code
pkinit_client_tryagain(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -1171,7 +1173,6 @@ pkinit_client_tryagain(krb5_context context,
X509_NAME *xn = NULL;
STACK_OF(PKCS7_ISSUER_AND_SERIAL) *sk_is = NULL;
PKCS7_ISSUER_AND_SERIAL *is = NULL;
- STACK_OF(ASN1_OCTET_STRING) *sk_id = NULL;
ASN1_OCTET_STRING *id = NULL;
if (reqctx->patype != in_padata->pa_type)
@@ -1181,7 +1182,7 @@ pkinit_client_tryagain(krb5_context context,
#ifdef DEBUG_ASN1
print_buffer_bin(err_reply->e_data.data, err_reply->e_data.length, "/tmp/client_edata");
#endif
- retval = decode_krb5_typed_data(&err_reply->e_data, &typed_data);
+ retval = k5int_decode_krb5_typed_data(&err_reply->e_data, &typed_data);
if (retval) {
pkiDebug("decode_krb5_typed_data failed\n");
goto cleanup;
@@ -1201,7 +1202,7 @@ pkinit_client_tryagain(krb5_context context,
pkiDebug("trusted certifiers\n");
else
pkiDebug("invalid certificate\n");
- retval = decode_krb5_td_trusted_certifiers(&scratch, &krb5_trusted_certifiers);
+ retval = k5int_decode_krb5_td_trusted_certifiers(&scratch, &krb5_trusted_certifiers);
if (retval) {
pkiDebug("failed to decode sequence of trusted certifiers\n");
goto cleanup;
@@ -1294,6 +1295,7 @@ cleanup:
}
#define PKINIT_REQ_CTX_MAGIC 0xdeadbeef
+
void
pkinit_client_req_init(krb5_context context,
void *plugin_context,
@@ -1308,15 +1310,28 @@ pkinit_client_req_init(krb5_context context,
reqctx = (pkinit_req_context *) malloc(sizeof(*reqctx));
if (reqctx == NULL)
return;
+ memset(reqctx, 0, sizeof(*reqctx));
reqctx->magic = PKINIT_REQ_CTX_MAGIC;
+ reqctx->plugctx = plugin_context;
reqctx->dh = NULL;
reqctx->dh_size = 1024;
reqctx->require_eku = plgctx->require_eku;
reqctx->require_san = plgctx->require_san;
+ reqctx->dh_or_rsa = plgctx->dh_or_rsa;
reqctx->require_hostname_match = 0;
reqctx->allow_upn = plgctx->allow_upn;
reqctx->require_crl_checking = plgctx->require_crl_checking;
+#ifndef WITHOUT_PKCS11
+ reqctx->p11_module_name = strdup(PKCS11_MODNAME);
+ reqctx->p11_module = NULL;
+ reqctx->slotid = 0;
+ reqctx->session = CK_INVALID_HANDLE;
+ reqctx->p11 = NULL;
+ reqctx->pkcs11_method = (getenv("PKCS11") != NULL);
+#else
+ reqctx->pkcs11_method = 0;
+#endif
*request_context = (void *) reqctx;
pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
@@ -1331,43 +1346,39 @@ pkinit_client_req_fini(krb5_context context,
pkinit_req_context *reqctx = (pkinit_req_context *)request_context;
pkiDebug("%s: received reqctx at %p\n", __FUNCTION__, reqctx);
-#ifndef WITHOUT_PKCS11
- pkinit_close_session();
-#endif
if (reqctx != NULL) {
if (reqctx->magic != PKINIT_REQ_CTX_MAGIC) {
pkiDebug("%s: Bad magic value (%x) in req ctx\n",
- __FUNCTION__, reqctx->magic);
+ __FUNCTION__, reqctx->magic);
return;
}
if (reqctx->dh != NULL) {
DH_free(reqctx->dh);
}
+#ifndef WITHOUT_PKCS11
+ if (reqctx->p11) {
+ if (reqctx->session) {
+ reqctx->p11->C_CloseSession(reqctx->session);
+ reqctx->session = CK_INVALID_HANDLE;
+ }
+ reqctx->p11->C_Finalize(NULL_PTR);
+ reqctx->p11 = NULL;
+ }
+ if (reqctx->p11_module) {
+ C_UnloadModule(reqctx->p11_module);
+ reqctx->p11_module = NULL;
+ }
+ if (reqctx->p11_module_name)
+ free(reqctx->p11_module_name);
+ if (reqctx->cert_id)
+ free(reqctx->cert_id);
+#endif
free(reqctx);
}
return;
}
-static int
-using_pkcs11(void)
-{
-#ifdef WITHOUT_PKCS11
- return 0;
-#else
- return (getenv("PKCS11") != NULL);
-#endif
-}
-
#ifndef WITHOUT_PKCS11
-
-static char *module_name = "opensc-pkcs11.so";
-static void *module = NULL;
-static unsigned int slotid = 0;
-static CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
-static CK_FUNCTION_LIST_PTR p11 = NULL;
-static CK_BYTE cert_id[MAX_ID_SIZE];
-static int cert_id_len;
-
void *
C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
{
@@ -1376,6 +1387,10 @@ C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
pkiDebug("loading module \"%s\"... ", modname);
handle = dlopen(modname, RTLD_NOW);
+ if (handle == NULL) {
+ pkiDebug("failed\n");
+ return NULL;
+ }
getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
dlclose(handle);
@@ -1394,105 +1409,138 @@ C_UnloadModule(void *handle)
}
static krb5_error_code
-pkinit_open_session(krb5_context context,
- krb5_prompter_fct prompter,
- void *prompter_data)
+pkinit_login(pkinit_req_context *reqctx, CK_TOKEN_INFO *tip)
{
- int r;
- char *s;
- char pin[32];
- char custom_module_name[100];
- krb5_data response_data;
+ krb5_data rdat;
krb5_prompt kprompt;
krb5_prompt_type prompt_type;
+ krb5_context ctx = reqctx->plugctx->context;
+ int r = 0;
- if (module != NULL)
- return 0;
+ if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+ rdat.data = NULL;
+ rdat.length = 0;
+ } else {
+ rdat.data = malloc(tip->ulMaxPinLen + 2);
+ rdat.length = tip->ulMaxPinLen + 1;
- /* Temporary pending use of krb5.conf */
- if ((s = getenv("PKCS11")) != NULL && strlen(s) > 0) {
- if (sscanf(s, "%99[^:]:%d", custom_module_name, &slotid) < 2)
- slotid = atoi(s);
- else
- module_name = custom_module_name;
- }
+ kprompt.prompt = "PIN";
+ kprompt.hidden = 1;
+ kprompt.reply = &rdat;
+ prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
- /* Load module, init, and open session */
- module = C_LoadModule(module_name, &p11);
- if (module == NULL) {
- pkiDebug("fail C_LoadModule\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ /* PROMPTER_INVOCATION */
+ krb5int_set_prompt_types(ctx, &prompt_type);
+ r = (*reqctx->prompter)(ctx, reqctx->prompter_data, NULL, NULL, 1, &kprompt);
+ krb5int_set_prompt_types(ctx, 0);
}
- if ((r = p11->C_Initialize(NULL)) != CKR_OK) {
- pkiDebug("fail C_Initialize %x\n", r);
- return KRB5KDC_ERR_PREAUTH_FAILED;
+
+ if (r == 0) {
+ r = reqctx->p11->C_Login(reqctx->session, CKU_USER, (u_char *) rdat.data,
+ rdat.length);
+ if (r != CKR_OK) {
+ pkiDebug("fail C_Login %x\n", r);
+ r = KRB5KDC_ERR_PREAUTH_FAILED;
+ }
}
- pkiDebug("opening slot %d\n", slotid);
- if ((r = p11->C_OpenSession(slotid, CKF_SERIAL_SESSION, NULL, NULL, &session)) !=
- CKR_OK) {
- pkiDebug("fail C_OpenSession %x\n", r);
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ if (rdat.data)
+ free(rdat.data);
+ return r;
+}
+
+static krb5_error_code
+pkinit_open_session(pkinit_req_context *reqctx)
+{
+ char *s, *cp, *ep;
+ int r, i, gotslot = 0;
+ CK_ULONG count = 0, id;
+ CK_SLOT_ID_PTR slotlist;
+ CK_TOKEN_INFO tinfo;
+
+ if (reqctx->p11_module != NULL)
+ return 0; /* session already open */
+
+ /* Temporary pending use of command line options and krb5.conf */
+ if ((s = getenv("PKCS11")) != NULL && (i = strlen(s)) > 0) {
+ id = strtol(s, &ep, 10);
+ if (*ep == '\0') {
+ /* got just a slotid */
+ reqctx->slotid = id;
+ gotslot = 1;
+ } else if (strchr(s, ':')) {
+ /* got a module name and slotid */
+ cp = malloc(i);
+ sscanf(s, "%[^:]:%d", cp, &reqctx->slotid);
+ free(reqctx->p11_module_name);
+ reqctx->p11_module_name = cp;
+ gotslot = 1;
+ } else {
+ /* got just a module name */
+ free(reqctx->p11_module_name);
+ reqctx->p11_module_name = strdup(s);
+ }
}
- response_data.data = pin;
- response_data.length = sizeof(pin);
+ /* Load module */
+ reqctx->p11_module = C_LoadModule(reqctx->p11_module_name, &reqctx->p11);
+ if (reqctx->p11_module == NULL)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
- kprompt.prompt = "PIN";
- kprompt.hidden = 1;
- kprompt.reply = &response_data;
- prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+ /* Init */
+ if ((r = reqctx->p11->C_Initialize(NULL)) != CKR_OK) {
+ pkiDebug("fail C_Initialize %x\n", r);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
- /* PROMPTER_INVOCATION */
- krb5int_set_prompt_types(context, &prompt_type);
- if ((r = ((*prompter)(context, prompter_data, NULL, NULL, 1, &kprompt)))) {
- krb5int_set_prompt_types(context, 0);
- return r;
+ /* Decide which slot to use */
+ if (!gotslot) {
+ if (reqctx->p11->C_GetSlotList(TRUE, NULL, &count) != CKR_OK)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ slotlist = (CK_SLOT_ID_PTR) malloc(count * sizeof (CK_SLOT_ID));
+ if (reqctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ /* take the first one for now */
+ reqctx->slotid = slotlist[0];
+ free(slotlist);
}
- krb5int_set_prompt_types(context, 0);
- if ((r = p11->C_Login(session, CKU_USER, (u_char *) pin, response_data.length)) != CKR_OK) {
- pkiDebug("fail C_Login %x\n", r);
+ /* Open session */
+ pkiDebug("init and open slotid %d (1 of %d)\n", reqctx->slotid, (int) count);
+ if ((r = reqctx->p11->C_OpenSession(reqctx->slotid, CKF_SERIAL_SESSION, NULL, NULL,
+ &reqctx->session)) != CKR_OK) {
+ pkiDebug("fail C_OpenSession %x\n", r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- return 0;
-}
+ /* Login if needed */
+ r = reqctx->p11->C_GetTokenInfo(reqctx->slotid, &tinfo);
+ if (r == CKR_OK && (tinfo.flags & CKF_LOGIN_REQUIRED))
+ r = pkinit_login(reqctx, &tinfo);
-static void
-pkinit_close_session(void)
-{
- if (p11) {
- if (session) {
- p11->C_CloseSession(session);
- session = CK_INVALID_HANDLE;
- }
- p11->C_Finalize(NULL_PTR);
- p11 = NULL;
- }
- if (module) {
- C_UnloadModule(module);
- module = NULL;
- }
+ return r;
}
#endif
krb5_error_code
-pkinit_get_client_cert(const char *principal,
+pkinit_get_client_cert(pkinit_req_context *reqctx,
+ const char *principal,
char *filename,
X509 ** client_cert)
{
#ifndef WITHOUT_PKCS11
+ CK_MECHANISM_TYPE_PTR mechp;
+ CK_MECHANISM_INFO info;
CK_OBJECT_CLASS cls;
- CK_OBJECT_HANDLE objs[MAX_N_OBJS];
+ CK_OBJECT_HANDLE obj;
CK_ATTRIBUTE attrs[2];
CK_ULONG count;
CK_CERTIFICATE_TYPE certtype;
- krb5_octet cert[MAX_CERT_SIZE];
+ CK_BYTE_PTR cert, cert_id;
const unsigned char *cp;
- int r;
+ int i, r;
#endif
- if (!using_pkcs11()) {
+ if (!reqctx->pkcs11_method) {
if ((*client_cert = get_cert(filename)) == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
else
@@ -1504,7 +1552,37 @@ pkinit_get_client_cert(const char *principal,
return KRB5_PRINC_NOMATCH;
}
- pkiDebug("Reading cert for '%s' from card\n", principal);
+ if (pkinit_open_session(reqctx)) {
+ pkiDebug("can't open pkcs11 session\n");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ if ((r = reqctx->p11->C_GetMechanismList(reqctx->slotid, NULL, &count)) != CKR_OK
+ || count <= 0) {
+ pkiDebug("can't find any mechanisms %x\n", r);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
+ if (mechp == NULL)
+ return ENOMEM;
+ if ((r = reqctx->p11->C_GetMechanismList(reqctx->slotid, mechp, &count)) != CKR_OK)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ for (i = 0; i < count; i++) {
+ if ((r = reqctx->p11->C_GetMechanismInfo(reqctx->slotid, mechp[i], &info)) != CKR_OK)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+#ifdef DEBUG_MECHINFO
+ pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
+ if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
+ pkiDebug(" this mech is good for sign & decrypt\n");
+#endif
+ if (mechp[i] == CKM_RSA_PKCS) {
+ /* This seems backwards... */
+ reqctx->mech = (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
+ }
+ }
+ free(mechp);
+
+ pkiDebug("got %d mechs; reading certs for '%s' from card\n", (int) count, principal);
cls = CKO_CERTIFICATE;
attrs[0].type = CKA_CLASS;
@@ -1516,42 +1594,63 @@ pkinit_get_client_cert(const char *principal,
attrs[1].pValue = &certtype;
attrs[1].ulValueLen = sizeof certtype;
- if (p11->C_FindObjectsInit(session, attrs, 2) != CKR_OK) {
+ if (reqctx->p11->C_FindObjectsInit(reqctx->session, attrs, 2) != CKR_OK) {
pkiDebug("fail C_FindObjectsInit\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- /* Look for x.509 cert */
- if ((r = p11->C_FindObjects(session, objs, 6, &count)) != CKR_OK
- || count <= 0) {
- pkiDebug("can't find any certs %x\n", r);
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- p11->C_FindObjectsFinal(session);
- pkiDebug("found %d certs\n", (int) count);
+ for (i = 0; ; i++) {
+ /* Look for x.509 cert */
+ if ((r = reqctx->p11->C_FindObjects(reqctx->session, &obj, 1, &count)) != CKR_OK
+ || count <= 0) {
+ break;
+ }
- /*
- * Read the cert and id off the card.
- * I can't find any way to reliably get the size before doing the read.
- */
- attrs[0].type = CKA_VALUE;
- attrs[0].pValue = cert;
- attrs[0].ulValueLen = sizeof cert;
+ /* Get cert and id len */
+ attrs[0].type = CKA_VALUE;
+ attrs[0].pValue = NULL;
+ attrs[0].ulValueLen = 0;
- attrs[1].type = CKA_ID;
- attrs[1].pValue = cert_id;
- attrs[1].ulValueLen = sizeof cert_id;
+ attrs[1].type = CKA_ID;
+ attrs[1].pValue = NULL;
+ attrs[1].ulValueLen = 0;
- /* Just take the first one. */
- if ((r = p11->C_GetAttributeValue(session, objs[0], attrs, 2)) != CKR_OK) {
- pkiDebug("fail C_GetAttributeValue %x\n", r);
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
+ if ((r = reqctx->p11->C_GetAttributeValue(reqctx->session, obj, attrs, 2)) != CKR_OK
+ && r != CKR_BUFFER_TOO_SMALL) {
+ pkiDebug("fail C_GetAttributeValue len %x\n", r);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ cert = (CK_BYTE_PTR) malloc((size_t) attrs[0].ulValueLen);
+ cert_id = (CK_BYTE_PTR) malloc((size_t) attrs[1].ulValueLen);
+ if (cert == NULL || cert_id == NULL)
+ return ENOMEM;
+
+ /* Read the cert and id off the card */
+
+ attrs[0].type = CKA_VALUE;
+ attrs[0].pValue = cert;
+
+ attrs[1].type = CKA_ID;
+ attrs[1].pValue = cert_id;
- pkiDebug("cert size %d id %d\n", (int) attrs[0].ulValueLen, (int) cert_id[0]);
- cert_id_len = attrs[1].ulValueLen;
- cp = (unsigned char *) cert;
- *client_cert = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
+ if ((r = reqctx->p11->C_GetAttributeValue(reqctx->session, obj, attrs, 2)) != CKR_OK) {
+ pkiDebug("fail C_GetAttributeValue %x\n", r);
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ pkiDebug("cert %d size %d id %d idlen %d\n",
+ i, (int) attrs[0].ulValueLen, (int) cert_id[0], (int) attrs[1].ulValueLen);
+ /* Just take the first one */
+ if (i == 0) {
+ reqctx->cert_id = cert_id;
+ reqctx->cert_id_len = attrs[1].ulValueLen;
+ cp = (unsigned char *) cert;
+ *client_cert = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
+ } else
+ free(cert_id);
+ free(cert);
+ }
+ reqctx->p11->C_FindObjectsFinal(reqctx->session);
if (*client_cert == NULL)
return KRB5KDC_ERR_PREAUTH_FAILED;
#endif
@@ -1559,28 +1658,36 @@ pkinit_get_client_cert(const char *principal,
}
#ifndef WITHOUT_PKCS11
+
+/*
+ * Look for a key that's:
+ * 1. private
+ * 2. capable of the specified operation (usually signing or decrypting)
+ * 3. RSA (this may be wrong but it's all we can do for now)
+ * 4. matches the id of the cert we chose
+ *
+ * You must call pkinit_get_client_cert before calling pkinit_find_private_key
+ * (that's because we need the ID of the private key)
+ *
+ * pkcs11 says the id of the key doesn't have to match that of the cert, but
+ * I can't figure out any other way to decide which key to use.
+ *
+ * We should only find one key that fits all the requirements.
+ * If there are more than one, we just take the first one.
+ */
+
krb5_error_code
-pkinit_find_private_key(CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp)
+pkinit_find_private_key(pkinit_req_context *reqctx,
+ CK_ATTRIBUTE_TYPE usage,
+ CK_OBJECT_HANDLE *objp)
{
CK_OBJECT_CLASS cls;
- CK_OBJECT_HANDLE objs[MAX_N_OBJS];
CK_ATTRIBUTE attrs[4];
CK_ULONG count;
CK_BBOOL bool;
CK_KEY_TYPE keytype;
int r;
- /*
- * Look for a key that's:
- * 1. private
- * 2. capable of the specified operation (usually signing or decrypting)
- * 3. RSA (this may be wrong but it's all we can do for now)
- * 4. matches the id of the cert we chose
- *
- * pkcs11 says the id of the key doesn't have to match that of the cert, but
- * I can't figure out any other way to decide which key to use.
- */
-
cls = CKO_PRIVATE_KEY;
attrs[0].type = CKA_CLASS;
attrs[0].pValue = &cls;
@@ -1597,26 +1704,26 @@ pkinit_find_private_key(CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp)
attrs[2].ulValueLen = sizeof keytype;
attrs[3].type = CKA_ID;
- attrs[3].pValue = cert_id;
- attrs[3].ulValueLen = cert_id_len;
+ attrs[3].pValue = reqctx->cert_id;
+ attrs[3].ulValueLen = reqctx->cert_id_len;
- if (p11->C_FindObjectsInit(session, attrs, 4) != CKR_OK) {
+ if (reqctx->p11->C_FindObjectsInit(reqctx->session, attrs, 4) != CKR_OK) {
pkiDebug("krb5_pkinit_sign_data: fail C_FindObjectsInit\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- r = p11->C_FindObjects(session, objs, 6, &count);
- p11->C_FindObjectsFinal(session);
+ r = reqctx->p11->C_FindObjects(reqctx->session, objp, 1, &count);
+ reqctx->p11->C_FindObjectsFinal(reqctx->session);
pkiDebug("found %d private keys %x\n", (int) count, (int) r);
if (r != CKR_OK || count < 1)
return KRB5KDC_ERR_PREAUTH_FAILED;
- *objp = objs[0];
return 0;
}
#endif
krb5_error_code
-pkinit_decode_data(unsigned char *data,
+pkinit_decode_data(pkinit_req_context *reqctx,
+ unsigned char *data,
int data_len,
unsigned char **decoded_data,
int *decoded_data_len,
@@ -1627,11 +1734,11 @@ pkinit_decode_data(unsigned char *data,
CK_OBJECT_HANDLE obj;
CK_ULONG len;
CK_MECHANISM mech;
- unsigned char txtbuf[4096], *cp;
+ unsigned char *cp;
int r;
#endif
- if (!using_pkcs11()) {
+ if (!reqctx->pkcs11_method) {
if (decode_data(decoded_data, decoded_data_len, data, data_len,
filename, cert) <= 0) {
pkiDebug("failed to decode data\n");
@@ -1641,51 +1748,55 @@ pkinit_decode_data(unsigned char *data,
}
#ifndef WITHOUT_PKCS11
- pkinit_find_private_key(CKA_DECRYPT, &obj);
+ if (pkinit_open_session(reqctx)) {
+ pkiDebug("can't open pkcs11 session\n");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ pkinit_find_private_key(reqctx, CKA_DECRYPT, &obj);
mech.mechanism = CKM_RSA_PKCS;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- if ((r = p11->C_DecryptInit(session, &mech, obj)) != CKR_OK) {
+ if ((r = reqctx->p11->C_DecryptInit(reqctx->session, &mech, obj)) != CKR_OK) {
pkiDebug("fail C_DecryptInit %x\n", (int) r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
-
- len = sizeof txtbuf;
- pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
- if ((r = p11->C_Decrypt(session, (krb5_octet *) data, (u_int) data_len, txtbuf, &len)) !=
+ cp = malloc((size_t) data_len);
+ if (cp == NULL)
+ return ENOMEM;
+ len = data_len;
+ if ((r = reqctx->p11->C_Decrypt(reqctx->session, data, (CK_ULONG) data_len, cp, &len)) !=
CKR_OK) {
pkiDebug("fail C_Decrypt %x\n", (int) r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- pkiDebug("txt size %d\n", (int) len);
- cp = malloc(len);
- if (cp == NULL)
- return ENOMEM;
- memcpy(cp, txtbuf, len);
+ pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
*decoded_data_len = len;
*decoded_data = cp;
- return 0;
#endif
+
+ return 0;
}
krb5_error_code
-pkinit_sign_data(unsigned char *data,
- int data_len,
- unsigned char **sig,
- int *sig_len,
- char *filename)
+pkinit_sign_data(pkinit_req_context *reqctx,
+ unsigned char *data,
+ int data_len,
+ unsigned char **sig,
+ int *sig_len,
+ char *filename)
{
#ifndef WITHOUT_PKCS11
CK_OBJECT_HANDLE obj;
CK_ULONG len;
CK_MECHANISM mech;
- unsigned char sigbuf[1024], *cp;
+ unsigned char *cp;
int r;
#endif
- if (!using_pkcs11()) {
+ if (reqctx == NULL || !reqctx->pkcs11_method) {
if (create_signature(sig, sig_len, data, data_len, filename) != 0) {
pkiDebug("failed to create the signature\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
@@ -1694,33 +1805,48 @@ pkinit_sign_data(unsigned char *data,
}
#ifndef WITHOUT_PKCS11
- pkinit_find_private_key(CKA_SIGN, &obj);
+ if (pkinit_open_session(reqctx)) {
+ pkiDebug("can't open pkcs11 session\n");
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ pkinit_find_private_key(reqctx, CKA_SIGN, &obj);
- mech.mechanism = CKM_SHA1_RSA_PKCS;
+ mech.mechanism = reqctx->mech;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- if ((r = p11->C_SignInit(session, &mech, obj)) != CKR_OK) {
+ if ((r = reqctx->p11->C_SignInit(reqctx->session, &mech, obj)) != CKR_OK) {
pkiDebug("fail C_SignInit %x\n", (int) r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- len = sizeof sigbuf;
- pkiDebug("signing %d -> %d\n", (int) data_len, (int) len);
- if ((r = p11->C_Sign(session, (krb5_octet *) data, (u_int) data_len, sigbuf, &len)) !=
- CKR_OK) {
+ /*
+ * Key len would give an upper bound on sig size, but there's no way to
+ * get that. So guess, and if it's too small, re-malloc.
+ */
+ len = PK_SIGLEN_GUESS;
+ cp = malloc((size_t) len);
+ if (cp == NULL)
+ return ENOMEM;
+
+ r = reqctx->p11->C_Sign(reqctx->session, data, (CK_ULONG) data_len, cp, &len);
+ if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
+ free(cp);
+ pkiDebug("C_Sign realloc %d\n", (int) len);
+ cp = malloc((size_t) len);
+ r = reqctx->p11->C_Sign(reqctx->session, data, (CK_ULONG) data_len, cp, &len);
+ }
+ if (r != CKR_OK) {
pkiDebug("fail C_Sign %x\n", (int) r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
- pkiDebug("sig size %d\n", (int) len);
- cp = malloc(len);
- if (cp == NULL)
- return ENOMEM;
- memcpy(cp, sigbuf, len);
+ pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
*sig_len = len;
*sig = cp;
- return 0;
#endif
+
+ return 0;
}
static krb5_error_code
@@ -2090,6 +2216,162 @@ errout:
return retval;
}
+static krb5_error_code
+handle_gic_opt(krb5_context context,
+ pkinit_context *plgctx,
+ char *attr,
+ char *value)
+{
+ int i, code;
+ struct stat statbuf;
+ char *colon, *sep, *residual;
+#define KS_FILE 1
+#define KS_PKCS11 2
+ int keyset;
+
+ /*
+ * XXX This is all just a hack right now... XXX
+ */
+ /*
+ * Would like to call something like "pkinit_set_identity()" or
+ * pkinit_set_user_identity() here...
+ */
+ if (strcmp(attr, "X509_user_identity") == 0) {
+ residual = strchr(value, ':');
+ if (residual) {
+ int typelen;
+ residual++; /* skip past colon */
+ typelen = residual - value;
+ if (strncmp(value, "FILE:", typelen) == 0) {
+ keyset = KS_FILE;
+ } else if (strncmp(value, "PKCS11:", typelen) == 0) {
+ keyset = KS_PKCS11;
+ } else {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Unsupported key set type while processing '%s'\n", value);
+ return KRB5_PREAUTH_FAILED;
+ }
+ } else {
+ keyset = KS_FILE;
+ residual = value;
+ }
+
+ switch (keyset) {
+ int certlen;
+ char certbuf[256];
+ char keybuf[256];
+ case KS_FILE:
+ sep = strchr(residual, ',');
+ if (sep) {
+ certlen = sep - residual;
+ strncpy(certbuf, residual, certlen);
+ certbuf[certlen] = '\0';
+ strncpy(keybuf, ++sep, sizeof keybuf);
+ keybuf[sizeof(keybuf) - 1] = '\0';
+ } else {
+ strncpy(certbuf, residual, sizeof certbuf);
+ certbuf[sizeof(certbuf) - 1] = '\0';
+ strncpy(keybuf, residual, sizeof keybuf);
+ keybuf[sizeof(keybuf) - 1] = '\0';
+ }
+ if ((code = stat(certbuf, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat certificate file '%s'", certbuf);
+ return KRB5_PREAUTH_FAILED;
+ }
+ if ((code = stat(keybuf, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat private key file '%s'", keybuf);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting X509_USER_CERT to '%s'\n", certbuf);
+ setenv("X509_USER_CERT", certbuf, 1);
+ pkiDebug("Setting X509_USER_KEY to '%s'\n", keybuf);
+ setenv("X509_USER_KEY", keybuf, 1);
+ break;
+ case KS_PKCS11:
+ if ((code = stat(residual, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat pkcs11 library '%s'", residual);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting PKCS11 to '%s'\n", residual);
+ setenv("PKCS11", residual, 1);
+ break;
+ default:
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Internal error parsing X509_user_identity\n");
+ return KRB5_PREAUTH_FAILED;
+ break;
+ }
+ } else if (strcmp(attr, "X509_anchors") == 0) {
+ /* Would like to call something like "pkinit_add_anchors() here */
+ if ((code = stat(value, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat X509_anchors directory '%s'",
+ value);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting X509_CA_DIR to '%s'\n", value);
+ setenv("X509_CA_DIR", value, 1);
+ } else if (strcmp(attr, "flag_RSA_PROTOCOL") == 0) {
+ if (strcmp(value, "yes") == 0) {
+ pkiDebug("Setting flag to use RSA_PROTOCOL\n");
+ plgctx->dh_or_rsa = RSA_PROTOCOL;
+ }
+ }
+#if 0
+ if (strcmp(attr, "client_cert") == 0) {
+ if ((code = stat(value, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat '%s' file '%s'", attr, value);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting X509_USER_CERT to '%s'\n", value);
+ setenv("X509_USER_CERT", value, 1);
+ }
+ if (strcmp(attr, "client_key") == 0) {
+ if ((code = stat(value, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat '%s' file '%s'", attr, value);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting X509_USER_KEY to '%s'\n", value);
+ setenv("X509_USER_KEY", value, 1);
+ }
+ if (strcmp(attr, "client_ca_dir") == 0) {
+ if ((code = stat(value, &statbuf)) != 0) {
+ krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
+ "Could not stat '%s' directory '%s'",
+ attr, value);
+ return KRB5_PREAUTH_FAILED;
+ }
+ pkiDebug("Setting X509_CA_DIR to '%s'\n", value);
+ setenv("X509_CA_DIR", value, 1);
+ }
+#endif
+ return 0;
+}
+
+static krb5_error_code
+pkinit_client_gic_opt(krb5_context context,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+ int i;
+ krb5_error_code retval;
+ pkinit_context *plgctx = (pkinit_context *)plugin_context;
+
+ pkiDebug("(pkinit) received '%s' = '%s'\n", attr, value);
+ retval = handle_gic_opt(context, plgctx, attr, value);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
static void
pkinit_client_plugin_fini(krb5_context context, void *blob)
{
@@ -2110,4 +2392,5 @@ struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
pkinit_client_req_fini, /* (*client_req_fini) */
pkinit_client_process, /* (*process) */
pkinit_client_tryagain, /* (*tryagain) */
+ pkinit_client_gic_opt /* (*gic_opt) */
};
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index 90a1eb3..f4d62bf 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -198,9 +198,10 @@ static int openssl_callback (int, X509_STORE_CTX *);
static int openssl_callback_ignore_crls (int, X509_STORE_CTX *);
static int pkcs7_decrypt
- (PKCS7 *p7, X509 *cert, BIO *bio, char *filename);
+ (pkinit_req_context *reqctx, PKCS7 *p7, X509 *cert, BIO *bio, char *filename);
-static BIO * pkcs7_dataDecode(PKCS7 *p7, X509 *pcert, char *filename);
+static BIO * pkcs7_dataDecode
+ (pkinit_req_context *reqctx,PKCS7 *p7, X509 *pcert, char *filename);
/* This handy macro borrowed from crypto/x509v3/v3_purp.c */
#define ku_reject(x, usage) \
@@ -210,16 +211,23 @@ krb5_error_code
pkinit_lib_init(krb5_context context, void **blob)
{
pkinit_context *plgctx;
- krb5_error_code retval = ENOMEM;
+ krb5_error_code retval;
int tmp = 0;
+ retval = pkinit_accessor_init();
+ if (retval)
+ goto out;
+
+ retval = ENOMEM;
plgctx = (pkinit_context *) calloc(1, sizeof(*plgctx));
if (plgctx == NULL)
goto out;
plgctx->magic = PKINIT_CTX_MAGIC;
+ plgctx->context = context;
plgctx->require_eku = 1;
plgctx->require_san = 1;
+ plgctx->dh_or_rsa = DH_PROTOCOL;
plgctx->allow_upn = 0;
plgctx->require_crl_checking = 0;
@@ -583,7 +591,8 @@ pkcs7_signeddata_create(unsigned char *data,
X509 * cert,
char *filename,
ASN1_OBJECT *oid,
- krb5_context context)
+ krb5_context context,
+ pkinit_req_context *reqctx)
{
krb5_error_code retval = ENOMEM;
PKCS7 *p7 = NULL, *inner_p7 = NULL;
@@ -593,13 +602,19 @@ pkcs7_signeddata_create(unsigned char *data,
ASN1_TYPE *pkinit_data = NULL;
STACK_OF(X509) * cert_stack = NULL;
ASN1_OCTET_STRING *digest_attr = NULL;
- EVP_MD_CTX ctx;
+ EVP_MD_CTX ctx, ctx2;
const EVP_MD *md_tmp;
- unsigned char md_data[EVP_MAX_MD_SIZE], *abuf = NULL;
- unsigned int md_len, alen;
+ unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
+ unsigned char *digestInfo_buf = NULL, *abuf = NULL;
+ unsigned int md_len, md_len2, alen, digestInfo_len;
STACK_OF(X509_ATTRIBUTE) * sk;
unsigned char *sig = NULL;
int sig_len = 0;
+ char *dirname = NULL;
+ X509_ALGOR *alg = NULL;
+ ASN1_OCTET_STRING *digest = NULL;
+ int z = 0, alg_len = 0, digest_len = 0;
+ unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
/* start creating PKCS7 data */
if ((p7 = PKCS7_new()) == NULL)
@@ -612,11 +627,46 @@ pkcs7_signeddata_create(unsigned char *data,
if (!ASN1_INTEGER_set(p7s->version, 1))
goto cleanup;
- /* create a cert chain */
+ /* create a cert chain that has at least the signer's certificate */
if ((cert_stack = sk_X509_new_null()) == NULL)
goto cleanup;
+
+ if (get_filename(&dirname, "X509_CA_DIR", 1) != 0) {
+ pkiDebug("only including signer's certificate\n");
+ sk_X509_push(cert_stack, X509_dup(cert));
+ } else {
+ /* create a cert chain */
+ X509_STORE *certstore = NULL;
+ X509_STORE_CTX certctx;
+ STACK_OF(X509) *certstack = NULL;
+ char buf[256];
+ int i = 0, size = 0;
+
+ if ((certstore = X509_STORE_new()) == NULL)
+ goto cleanup;
+ if(!X509_STORE_load_locations(certstore, NULL, dirname))
+ goto cleanup;
+ pkiDebug("building certificate chain from dir = %s\n", dirname);
+ X509_STORE_set_verify_cb_func(certstore, openssl_callback);
+ X509_STORE_CTX_init(&certctx, certstore, cert, NULL);
+ if (!X509_verify_cert(&certctx))
+ goto cleanup;
+ certstack = X509_STORE_CTX_get1_chain(&certctx);
+ size = sk_X509_num(certstack);
+ pkiDebug("size of certificate chain = %d\n", size);
+ for(i = 0; i < size - 1; i++) {
+ X509 *x = sk_X509_value(certstack, i);
+ X509_NAME_oneline(X509_get_subject_name(x), buf, 256);
+ pkiDebug("cert #%d: %s\n", i, buf);
+ sk_X509_push(cert_stack, X509_dup(x));
+ }
+ X509_STORE_CTX_cleanup(&certctx);
+ X509_STORE_free(certstore);
+ sk_X509_free(certstack);
+ }
+ if (dirname != NULL)
+ free(dirname);
p7s->cert = cert_stack;
- sk_X509_push(cert_stack, X509_dup(cert));
/* fill-in PKCS7_SIGNER_INFO */
if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
@@ -647,7 +697,7 @@ pkcs7_signeddata_create(unsigned char *data,
/* Set sig algs */
if (p7si->digest_enc_alg->parameter != NULL)
ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_rsaEncryption);
+ p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
goto cleanup;
p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
@@ -675,12 +725,69 @@ pkcs7_signeddata_create(unsigned char *data,
alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
if (abuf == NULL)
- goto cleanup;
-
- retval = pkinit_sign_data(abuf, alen, &sig, &sig_len, filename);
+ goto cleanup2;
+
+ /* ActiveCard can only do RSAEncryption */
+ /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
+ * function and the hash value into an ASN.1 value of type DigestInfo
+ * DigestInfo::=SEQUENCE{
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING }
+ */
+ if (reqctx && reqctx->pkcs11_method &&
+ reqctx->mech == CKM_RSA_PKCS) {
+ pkiDebug("mech = CKM_RSA_PKCS\n");
+ EVP_MD_CTX_init(&ctx2);
+ EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
+ EVP_DigestUpdate(&ctx2, abuf, alen);
+ EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
+
+ alg = X509_ALGOR_new();
+ if (alg == NULL)
+ goto cleanup2;
+ alg->algorithm = OBJ_nid2obj(NID_sha1);
+ alg->parameter = NULL;
+ alg_len = i2d_X509_ALGOR(alg, NULL);
+ alg_buf = malloc(alg_buf);
+ if (alg_buf == NULL)
+ goto cleanup2;
+
+ digest = ASN1_OCTET_STRING_new();
+ if (digest == NULL)
+ goto cleanup2;
+ ASN1_OCTET_STRING_set(digest, md_data2, md_len2);
+ digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
+ digest_buf = malloc(digest_len);
+ if (digest_buf == NULL)
+ goto cleanup2;
+
+ digestInfo_len = ASN1_object_size(1, alg_len + digest_len,
+ V_ASN1_SEQUENCE);
+ y = digestInfo_buf = malloc(digestInfo_len);
+ if (digestInfo_buf == NULL)
+ goto cleanup2;
+ ASN1_put_object(&y, 1, alg_len + digest_len, V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL);
+ i2d_X509_ALGOR(alg, &y);
+ i2d_ASN1_OCTET_STRING(digest, &y);
+#ifdef DEBUG_SIG
+ pkiDebug("signing buffer\n");
+ print_buffer(digestInfo_buf, digestInfo_len);
+ print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/client_tosign");
+#endif
+ retval = pkinit_sign_data(reqctx, digestInfo_buf, digestInfo_len,
+ &sig, &sig_len, filename);
+ } else {
+ if (reqctx != NULL)
+ pkiDebug("mech = %s\n", reqctx->pkcs11_method?"CKM_SHA1_RSA_PKCS":"FS");
+ retval = pkinit_sign_data(reqctx, abuf, alen, &sig, &sig_len, filename);
+ }
+#ifdef DEBUG_SIG
+ print_buffer(sig, sig_len);
+#endif
free(abuf);
if (retval)
- goto cleanup;
+ goto cleanup2;
/* Add signature */
if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig, sig_len)) {
@@ -689,20 +796,20 @@ pkcs7_signeddata_create(unsigned char *data,
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
pkiDebug("failed to add a signed digest attribute\n");
- goto cleanup;
+ goto cleanup2;
}
/* adder signer_info to pkcs7 signed */
if (!PKCS7_add_signer(p7, p7si))
- goto cleanup;
+ goto cleanup2;
/* start on adding data to the pkcs7 signed */
if ((inner_p7 = PKCS7_new()) == NULL)
- goto cleanup;
+ goto cleanup2;
if ((pkinit_data = ASN1_TYPE_new()) == NULL)
- goto cleanup;
+ goto cleanup2;
pkinit_data->type = V_ASN1_OCTET_STRING;
if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
- goto cleanup;
+ goto cleanup2;
if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
data_len)) {
unsigned long err = ERR_peek_error();
@@ -710,11 +817,11 @@ pkcs7_signeddata_create(unsigned char *data,
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
pkiDebug("failed to add pkcs7 data\n");
- goto cleanup;
+ goto cleanup2;
}
if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
- goto cleanup;
+ goto cleanup2;
if (p7s->contents != NULL)
PKCS7_free(p7s->contents);
p7s->contents = inner_p7;
@@ -726,11 +833,11 @@ pkcs7_signeddata_create(unsigned char *data,
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
pkiDebug("failed to der encode pkcs7\n");
- goto cleanup;
+ goto cleanup2;
}
if ((p = *signed_data =
(unsigned char *) malloc(*signed_data_len)) == NULL)
- goto cleanup;
+ goto cleanup2;
/* DER encode PKCS7 data */
retval = i2d_PKCS7(p7, &p);
@@ -740,14 +847,27 @@ pkcs7_signeddata_create(unsigned char *data,
krb5_set_error_message(context, retval, "%s\n",
ERR_error_string(err, NULL));
pkiDebug("failed to der encode pkcs7\n");
- goto cleanup;
+ goto cleanup2;
}
retval = 0;
+ cleanup2:
+ EVP_MD_CTX_cleanup(&ctx);
+ if (reqctx && reqctx->pkcs11_method && reqctx->mech == CKM_RSA_PKCS)
+ EVP_MD_CTX_cleanup(&ctx2);
+ if (alg != NULL)
+ X509_ALGOR_free(alg);
+ if (digest != NULL)
+ ASN1_OCTET_STRING_free(digest);
+ if (alg_buf != NULL)
+ free(alg_buf);
+ if (digest_buf != NULL)
+ free(digest_buf);
+ if (digestInfo_buf != NULL)
+ free(digestInfo_buf);
cleanup:
if (p7 != NULL)
PKCS7_free(p7);
- EVP_MD_CTX_cleanup(&ctx);
if (sig != NULL)
free(sig);
@@ -782,6 +902,9 @@ pkcs7_signeddata_verify(unsigned char *signed_data,
pkiDebug("failed to get the name of the directory for trusted CAs\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
+#ifdef DEBUG_ASN1
+ print_buffer_bin(p, signed_data_len, "/tmp/kdc_signeddata");
+#endif
if ((p7 = d2i_PKCS7(NULL, &p, signed_data_len)) == NULL) {
unsigned long err = ERR_peek_error();
@@ -825,9 +948,24 @@ pkcs7_signeddata_verify(unsigned char *signed_data,
goto cleanup;
if (!X509_STORE_CTX_init(&cert_ctx, store, x, p7->d.sign->cert))
goto cleanup;
+ if (p7->d.sign->cert != NULL) {
+ int sk_size = sk_X509_num(p7->d.sign->cert);
+ int i;
+ char buf[256];
+ pkiDebug("received cert chain of size %d\n", sk_size);
+ for (i = 0; i < sk_size; i++) {
+ X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, i);
+ X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, 256);
+ pkiDebug("cert #%d: %s\n", i, buf);
+ }
+ }
i = X509_verify_cert(&cert_ctx);
if (i <= 0) {
int j = X509_STORE_CTX_get_error(&cert_ctx);
+ int sk_size = sk_X509_num(p7->d.sign->cert);
+ int i;
+ char buf[256];
+
*cert = X509_dup(cert_ctx.current_cert);
switch(j) {
case X509_V_ERR_CERT_REVOKED:
@@ -840,9 +978,17 @@ pkcs7_signeddata_verify(unsigned char *signed_data,
default:
retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
}
+ X509_NAME_oneline(X509_get_subject_name(*cert), buf, 256);
+ pkiDebug("problem with cert DN = %s (error=%d)\n", buf, j);
pkiDebug("%s\n", X509_verify_cert_error_string(j));
krb5_set_error_message(context, retval, "%s\n",
X509_verify_cert_error_string(j));
+ pkiDebug("received cert chain of size %d\n", sk_size);
+ for (i = 0; i < sk_size; i++) {
+ X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, i);
+ X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, 256);
+ pkiDebug("cert #%d: %s\n", i, buf);
+ }
}
X509_STORE_CTX_cleanup(&cert_ctx);
if (i <= 0)
@@ -937,15 +1083,16 @@ pkcs7_envelopeddata_verify(unsigned char *enveloped_data,
X509 *client_cert,
char *key_filename,
krb5_preauthtype pa_type,
- pkinit_context *plgctx,
X509 ** cert,
- krb5_context context)
+ pkinit_req_context *reqctx)
{
krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
PKCS7 *p7 = NULL;
BIO *out = NULL;
int i = 0, size = 0;
const unsigned char *p = enveloped_data;
+ krb5_context context = reqctx->plugctx->context;
+ pkinit_context *plgctx = reqctx->plugctx;
int tmp_buf_len = 0, tmp_buf2_len = 0;
unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL;
@@ -966,7 +1113,7 @@ pkcs7_envelopeddata_verify(unsigned char *enveloped_data,
}
out = BIO_new(BIO_s_mem());
- if (pkcs7_decrypt(p7, client_cert, out, key_filename)) {
+ if (pkcs7_decrypt(reqctx, p7, client_cert, out, key_filename)) {
pkiDebug("PKCS7 decryption successful\n");
} else {
unsigned long err = ERR_peek_error();
@@ -1094,7 +1241,7 @@ pkcs7_envelopeddata_create(unsigned char *key_pack,
unsigned char *p = NULL;
retval = pkcs7_signeddata_create(key_pack, key_pack_len, &signed_data,
- &signed_data_len, kdc_cert, filename, oid, context);
+ &signed_data_len, kdc_cert, filename, oid, context, NULL);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
goto cleanup;
@@ -1191,7 +1338,6 @@ verify_id_pkinit_san(X509 *x,
pkiDebug("unable to retrieve subject alt name ext\n");
goto cleanup;
}
-
pkiDebug("found %d subject alt name extension(s)\n",
sk_GENERAL_NAME_num(ialt));
@@ -1208,7 +1354,7 @@ verify_id_pkinit_san(X509 *x,
#ifdef DEBUG_ASN1
print_buffer_bin(name.data, name.length, "/tmp/pkinit_san");
#endif
- ret = decode_krb5_principal_name(&name, out);
+ ret = k5int_decode_krb5_principal_name(&name, out);
} else if (plgctx->allow_upn &&
!OBJ_cmp(plgctx->id_pkinit_san9,
gen->d.otherName->type_id)) {
@@ -1807,7 +1953,7 @@ create_krb5_trustedCertifiers(STACK_OF(X509) * sk,
}
static int
-pkcs7_decrypt(PKCS7 *p7, X509 *cert, BIO *data, char *filename)
+pkcs7_decrypt(pkinit_req_context *reqctx, PKCS7 *p7, X509 *cert, BIO *data, char *filename)
{
int flags = PKCS7_BINARY;
BIO *tmpmem = NULL;
@@ -1822,7 +1968,7 @@ pkcs7_decrypt(PKCS7 *p7, X509 *cert, BIO *data, char *filename)
return 0;
}
- if(!(tmpmem = pkcs7_dataDecode(p7, cert, filename))) {
+ if(!(tmpmem = pkcs7_dataDecode(reqctx, p7, cert, filename))) {
pkiDebug("unable to decrypt pkcs7 object\n");
return 0;
}
@@ -1838,7 +1984,7 @@ pkcs7_decrypt(PKCS7 *p7, X509 *cert, BIO *data, char *filename)
}
static BIO *
-pkcs7_dataDecode(PKCS7 *p7, X509 *pcert, char *filename)
+pkcs7_dataDecode(pkinit_req_context *reqctx, PKCS7 *p7, X509 *pcert, char *filename)
{
int i = 0, jj= 0, jj2 = 0, tmp_len = 0;
BIO *out=NULL,*etmp=NULL,*bio=NULL;
@@ -1904,7 +2050,7 @@ pkcs7_dataDecode(PKCS7 *p7, X509 *pcert, char *filename)
if (pcert == NULL) {
for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
- jj = pkinit_decode_data(M_ASN1_STRING_data(ri->enc_key),
+ jj = pkinit_decode_data(reqctx, M_ASN1_STRING_data(ri->enc_key),
M_ASN1_STRING_length(ri->enc_key),
&tmp, &tmp_len, filename, pcert);
if (jj) {
@@ -1927,7 +2073,7 @@ pkcs7_dataDecode(PKCS7 *p7, X509 *pcert, char *filename)
}
}
else {
- jj = pkinit_decode_data(M_ASN1_STRING_data(ri->enc_key),
+ jj = pkinit_decode_data(reqctx, M_ASN1_STRING_data(ri->enc_key),
M_ASN1_STRING_length(ri->enc_key),
&tmp, &tmp_len, filename, pcert);
if (jj || tmp_len <= 0) {
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 145ddc4..77ce478 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -43,6 +43,10 @@
#include <openssl/asn1_mac.h>
#include <openssl/sha.h>
+#ifndef WITHOUT_PKCS11
+#include <opensc/pkcs11.h>
+#endif
+
#include "pkinit.h"
#ifdef DEBUG
@@ -51,30 +55,40 @@
#define pkiDebug(args...)
#endif
-static krb5_error_code pkinit_server_get_edata
- (krb5_context context, krb5_kdc_req * request,
- struct _krb5_db_entry_new * client,
- struct _krb5_db_entry_new * server,
- preauth_get_entry_data_proc server_get_entry_data,
- void *pa_plugin_context,
- krb5_pa_data * data);
-
-static krb5_error_code pkinit_server_verify_padata
- (krb5_context context, struct _krb5_db_entry_new * client,
- krb5_data *req_pkt, krb5_kdc_req * request,
- krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data * data,
- preauth_get_entry_data_proc server_get_entry_data,
- void *pa_plugin_context, void **pa_request_context,
- krb5_data **e_data);
-
-static krb5_error_code pkinit_server_return_padata
- (krb5_context context, krb5_pa_data * padata,
- struct _krb5_db_entry_new * client, krb5_data *req_pkt,
- krb5_kdc_req * request, krb5_kdc_rep * reply,
- struct _krb5_key_data * client_key,
- krb5_keyblock * encrypting_key, krb5_pa_data ** send_pa,
- preauth_get_entry_data_proc server_get_entry_data,
- void *pa_plugin_context, void **pa_request_context);
+static krb5_error_code
+pkinit_server_get_edata(krb5_context context,
+ krb5_kdc_req * request,
+ struct _krb5_db_entry_new * client,
+ struct _krb5_db_entry_new * server,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_plugin_context,
+ krb5_pa_data * data);
+
+static krb5_error_code
+pkinit_server_verify_padata(krb5_context context,
+ struct _krb5_db_entry_new * client,
+ krb5_data *req_pkt,
+ krb5_kdc_req * request,
+ krb5_enc_tkt_part * enc_tkt_reply,
+ krb5_pa_data * data,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_plugin_context,
+ void **pa_request_context,
+ krb5_data **e_data);
+
+static krb5_error_code
+pkinit_server_return_padata(krb5_context context,
+ krb5_pa_data * padata,
+ struct _krb5_db_entry_new * client,
+ krb5_data *req_pkt,
+ krb5_kdc_req * request,
+ krb5_kdc_rep * reply,
+ struct _krb5_key_data * client_key,
+ krb5_keyblock * encrypting_key,
+ krb5_pa_data ** send_pa,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_plugin_context,
+ void **pa_request_context);
static int pkinit_server_get_flags
(krb5_context kcontext, krb5_preauthtype patype);
@@ -233,7 +247,7 @@ pkinit_create_sequence_of_principal_identifiers(STACK_OF(X509) *sk, int type, kr
pkiDebug("create_krb5_trustedCertifiers failed\n");
goto cleanup;
}
- retval = encode_krb5_td_trusted_certifiers(krb5_trusted_certifiers, &td_certifiers);
+ retval = k5int_encode_krb5_td_trusted_certifiers(krb5_trusted_certifiers, &td_certifiers);
if (retval) {
pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
goto cleanup;
@@ -248,14 +262,14 @@ pkinit_create_sequence_of_principal_identifiers(STACK_OF(X509) *sk, int type, kr
}
typed_data[1] = NULL;
init_krb5_typed_data(&typed_data[0]);
- if (typed_data == NULL) {
+ if (typed_data[0] == NULL) {
retval = ENOMEM;
goto cleanup;
}
typed_data[0]->type = type;
typed_data[0]->length = td_certifiers->length;
typed_data[0]->data = td_certifiers->data;
- retval = encode_krb5_typed_data(typed_data, &data);
+ retval = k5int_encode_krb5_typed_data(typed_data, &data);
if (retval) {
pkiDebug("encode_krb5_typed_data failed\n");
goto cleanup;
@@ -439,7 +453,7 @@ pkinit_create_td_dh_parameters(pkinit_context *plgctx, krb5_data **out_data)
algId[0]->algorithm = dh_oid;
}
- retval = encode_krb5_td_dh_parameters(algId, &encoded_algId);
+ retval = k5int_encode_krb5_td_dh_parameters(algId, &encoded_algId);
if (retval)
goto cleanup;
#ifdef DEBUG_ASN1
@@ -459,7 +473,7 @@ pkinit_create_td_dh_parameters(pkinit_context *plgctx, krb5_data **out_data)
typed_data[0]->type = TD_DH_PARAMETERS;
typed_data[0]->length = encoded_algId->length;
typed_data[0]->data = encoded_algId->data;
- retval = encode_krb5_typed_data(typed_data, &data);
+ retval = k5int_encode_krb5_typed_data(typed_data, &data);
if (retval) {
pkiDebug("encode_krb5_typed_data failed\n");
goto cleanup;
@@ -576,6 +590,8 @@ pkinit_server_verify_padata(krb5_context context,
pkinit_context *plgctx = (pkinit_context *)pa_plugin_context;
krb5_preauthtype pa_type;
krb5_principal tmp_client;
+ krb5_checksum cksum = {0, 0, 0, NULL};
+ krb5_data *der_req = NULL;
pkiDebug("pkinit_verify_padata: entered!\n");
@@ -596,7 +612,7 @@ pkinit_server_verify_padata(krb5_context context,
case KRB5_PADATA_PK_AS_REQ:
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
pa_type = (int)data->pa_type;
- retval = decode_krb5_pa_pk_as_req(&scratch, &reqp);
+ retval = k5int_decode_krb5_pa_pk_as_req(&scratch, &reqp);
scratch.data = NULL;
scratch.length = 0;
if (retval) {
@@ -612,7 +628,7 @@ pkinit_server_verify_padata(krb5_context context,
case KRB5_PADATA_PK_AS_REQ_OLD:
pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
- retval = decode_krb5_pa_pk_as_req_draft9(&scratch, &reqp9);
+ retval = k5int_decode_krb5_pa_pk_as_req_draft9(&scratch, &reqp9);
scratch.data = NULL;
scratch.length = 0;
if (retval) {
@@ -668,12 +684,13 @@ pkinit_server_verify_padata(krb5_context context,
#endif
switch ((int)data->pa_type) {
case KRB5_PADATA_PK_AS_REQ:
- retval = decode_krb5_auth_pack(&scratch, &auth_pack);
+ retval = k5int_decode_krb5_auth_pack(&scratch, &auth_pack);
if (retval) {
pkiDebug("failed to decode krb5_auth_pack\n");
goto cleanup;
}
+ /* check dh parameters */
if (auth_pack->clientPublicValue != NULL) {
retval = server_check_dh(plgctx,
&auth_pack->clientPublicValue->algorithm.parameters,
@@ -684,6 +701,36 @@ pkinit_server_verify_padata(krb5_context context,
goto cleanup;
}
}
+ /* check the checksum */
+ retval = encode_krb5_kdc_req_body(request, &der_req);
+ if (retval) {
+ pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
+ goto cleanup;
+ }
+ retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
+ 0, der_req, &cksum);
+ if (retval) {
+ pkiDebug("unable to calculate AS REQ checksum\n");
+ goto cleanup;
+ }
+ if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
+ memcmp(cksum.contents,
+ auth_pack->pkAuthenticator.paChecksum.contents,
+ cksum.length)) {
+ pkiDebug("failed to match the checksum\n");
+#ifdef DEBUG_CKSUM
+ pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length);
+ print_buffer(req_pkt->data, req_pkt->length);
+ pkiDebug("received checksum type=%d size=%d ", auth_pack->pkAuthenticator.paChecksum.checksum_type, auth_pack->pkAuthenticator.paChecksum.length);
+ print_buffer(auth_pack->pkAuthenticator.paChecksum.contents, auth_pack->pkAuthenticator.paChecksum.length);
+ pkiDebug("expected checksum type=%d size=%d ", cksum.checksum_type, cksum.length);
+ print_buffer(cksum.contents, cksum.length);
+#endif
+
+ retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
+ goto cleanup;
+ }
+
/* check if kdcPkId present and match KDC's subjectIdentifier */
if (reqp->kdcPkId.data != NULL) {
PKCS7_ISSUER_AND_SERIAL *is = NULL;
@@ -716,7 +763,7 @@ pkinit_server_verify_padata(krb5_context context,
break;
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = decode_krb5_auth_pack_draft9(&scratch, &auth_pack9);
+ retval = k5int_decode_krb5_auth_pack_draft9(&scratch, &auth_pack9);
if (retval) {
pkiDebug("failed to decode krb5_auth_pack_draft9\n");
goto cleanup;
@@ -751,6 +798,10 @@ pkinit_server_verify_padata(krb5_context context,
auth_pack->clientPublicValue->algorithm.algorithm.data != NULL)
free(auth_pack->clientPublicValue->algorithm.algorithm.data);
free_krb5_auth_pack(&auth_pack);
+ if (cksum.contents != NULL)
+ free(cksum.contents);
+ if (der_req != NULL)
+ krb5_free_data(context, der_req);
break;
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
@@ -825,7 +876,7 @@ pkinit_server_return_padata(krb5_context context,
switch ((int)padata->pa_type) {
case KRB5_PADATA_PK_AS_REQ:
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
- retval = decode_krb5_pa_pk_as_req(&scratch, &reqp);
+ retval = k5int_decode_krb5_pa_pk_as_req(&scratch, &reqp);
if (retval) {
pkiDebug("decode_krb5_pa_pk_as_req failed");
goto cleanup;
@@ -840,7 +891,7 @@ pkinit_server_return_padata(krb5_context context,
pkiDebug("pkcs7_signeddata_verify failed\n");
goto cleanup;
}
- retval = decode_krb5_auth_pack(&scratch, &auth_pack);
+ retval = k5int_decode_krb5_auth_pack(&scratch, &auth_pack);
if (retval) {
pkiDebug("failed to decode krb5_auth_pack\n");
goto cleanup;
@@ -854,7 +905,7 @@ pkinit_server_return_padata(krb5_context context,
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD %d\n", padata->pa_type);
- retval = decode_krb5_pa_pk_as_req_draft9(&scratch, &reqp9);
+ retval = k5int_decode_krb5_pa_pk_as_req_draft9(&scratch, &reqp9);
if (retval) {
pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed");
goto cleanup;
@@ -869,7 +920,7 @@ pkinit_server_return_padata(krb5_context context,
pkiDebug("pkcs7_signeddata_verify failed");
goto cleanup;
}
- retval = decode_krb5_auth_pack_draft9(&scratch, &auth_pack9);
+ retval = k5int_decode_krb5_auth_pack_draft9(&scratch, &auth_pack9);
if (retval) {
pkiDebug("failed to decode krb5_auth_pack_draft9\n");
goto cleanup;
@@ -978,7 +1029,7 @@ pkinit_server_return_padata(krb5_context context,
dhkey_info.nonce = request->nonce;
dhkey_info.dhKeyExpiration = 0;
- retval = encode_krb5_kdc_dh_key_info(&dhkey_info, &encoded_dhkey_info);
+ retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info, &encoded_dhkey_info);
if (retval) {
pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
goto cleanup;
@@ -993,8 +1044,8 @@ pkinit_server_return_padata(krb5_context context,
encoded_dhkey_info->length,
&rep->u.dh_Info.dhSignedData.data,
&rep->u.dh_Info.dhSignedData.length,
- kdc_cert, filename,
- plgctx->id_pkinit_DHKeyData, context);
+ kdc_cert, filename, plgctx->id_pkinit_DHKeyData,
+ context, NULL);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
goto cleanup;
@@ -1005,7 +1056,7 @@ pkinit_server_return_padata(krb5_context context,
retval = pkcs7_signeddata_create(encoded_dhkey_info->data,
encoded_dhkey_info->length, &rep9->u.dhSignedData.data,
&rep9->u.dhSignedData.length, kdc_cert, filename,
- plgctx->id_pkinit_authData9, context);
+ plgctx->id_pkinit_authData9, context, NULL);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
goto cleanup;
@@ -1057,7 +1108,7 @@ pkinit_server_return_padata(krb5_context context,
krb5_copy_keyblock_contents(context, encrypting_key,
&key_pack->replyKey);
- retval = encode_krb5_reply_key_pack(key_pack,
+ retval = k5int_encode_krb5_reply_key_pack(key_pack,
&encoded_key_pack);
if (retval) {
pkiDebug("failed to encode reply_key_pack\n");
@@ -1087,7 +1138,7 @@ pkinit_server_return_padata(krb5_context context,
krb5_copy_keyblock_contents(context, encrypting_key,
&key_pack9->replyKey);
- retval = encode_krb5_reply_key_pack_draft9(key_pack9,
+ retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
&encoded_key_pack);
if (retval) {
pkiDebug("failed to encode reply_key_pack\n");
@@ -1132,11 +1183,11 @@ pkinit_server_return_padata(krb5_context context,
switch ((int)padata->pa_type) {
case KRB5_PADATA_PK_AS_REQ:
- retval = encode_krb5_pa_pk_as_rep(rep, &out_data);
+ retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
break;
case KRB5_PADATA_PK_AS_REP_OLD:
case KRB5_PADATA_PK_AS_REQ_OLD:
- retval = encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
+ retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
break;
}
if (retval) {
@@ -1144,7 +1195,8 @@ pkinit_server_return_padata(krb5_context context,
goto cleanup;
}
#ifdef DEBUG_ASN1
- print_buffer_bin(out_data->data, out_data->length, "/tmp/kdc_as_rep");
+ if (out_data != NULL)
+ print_buffer_bin(out_data->data, out_data->length, "/tmp/kdc_as_rep");
#endif
*send_pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c
index 46ea662..f858063 100644
--- a/src/plugins/preauth/wpse/wpse_main.c
+++ b/src/plugins/preauth/wpse/wpse_main.c
@@ -90,6 +90,7 @@ static krb5_error_code
client_process(krb5_context kcontext,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc client_get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -208,6 +209,21 @@ client_req_cleanup(krb5_context kcontext, void *plugin_context, void *req_contex
return;
}
+static krb5_error_code
+client_gic_opt(krb5_context kcontext,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+#ifdef DEBUG
+ fprintf(stderr, "(wpse) client_gic_opt: received '%s' = '%s'\n",
+ attr, value);
+#endif
+ return 0;
+}
+
+
/* Free state. */
static krb5_error_code
server_free_pa_request_context(krb5_context kcontext, void *plugin_context,
@@ -378,6 +394,7 @@ struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
client_req_cleanup, /* request fini function */
client_process, /* process function */
NULL, /* try_again function */
+ client_gic_opt /* get init creds opts function */
};
struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {