diff options
author | Sam Hartman <hartmans@mit.edu> | 2009-03-26 05:37:41 +0000 |
---|---|---|
committer | Sam Hartman <hartmans@mit.edu> | 2009-03-26 05:37:41 +0000 |
commit | c9485a59a77e98ad55e7b7e2f6eac835b55cd9ef (patch) | |
tree | a92b5a28334329a43b57509382b71f6745c2a72e | |
parent | 59c56c85575b47b1ea5e6599a7f7b1be9ca559f8 (diff) | |
download | krb5-c9485a59a77e98ad55e7b7e2f6eac835b55cd9ef.zip krb5-c9485a59a77e98ad55e7b7e2f6eac835b55cd9ef.tar.gz krb5-c9485a59a77e98ad55e7b7e2f6eac835b55cd9ef.tar.bz2 |
Implement Encrypted Challenge fast factor
Implement the encrypted challenge fast factor. As part of this,
expose an interface for a preauth method to request the FAST armor
key.
* plugins/preauth/encrypted_challenge: new plugin
* include/krb5/krb5.hin: constants (keyusages) for encrypted challenge
* include/k5-int.h krb5/os/accessor.c: expose interfaces needed by encrypted challenge
* kdc/kdc_preauth.c lib/krb5/krb/preauth2.c include/krb5/preauth_plugin.h: interface for
fast armor key
* kdc/do_as_req.c: make fast state available to preauth
* lib/krb5/krb/get_in_tkt.c: initialize etype based on etype of AS reply
* lib/krb5/krb/preauth2.c: Etype given to plugins tracked the same way as etype used internally
git-svn-id: svn://anonsvn.mit.edu/krb5/branches/fast@22145 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/Makefile.in | 1 | ||||
-rw-r--r-- | src/configure.in | 2 | ||||
-rw-r--r-- | src/include/k5-int.h | 16 | ||||
-rw-r--r-- | src/include/krb5/krb5.hin | 2 | ||||
-rw-r--r-- | src/include/krb5/preauth_plugin.h | 29 | ||||
-rw-r--r-- | src/kdc/do_as_req.c | 2 | ||||
-rw-r--r-- | src/kdc/kdc_preauth.c | 25 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 7 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth2.c | 39 | ||||
-rw-r--r-- | src/lib/krb5/os/accessor.c | 7 | ||||
-rw-r--r-- | src/plugins/preauth/encrypted_challenge/Makefile.in | 41 | ||||
-rw-r--r-- | src/plugins/preauth/encrypted_challenge/deps | 0 | ||||
-rw-r--r-- | src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports | 2 | ||||
-rw-r--r-- | src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c | 409 | ||||
-rw-r--r-- | src/plugins/preauth/fast_factor.h | 53 |
15 files changed, 620 insertions, 15 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 16349b8..dc80d2f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -12,6 +12,7 @@ mydir=. SUBDIRS=util include lib kdc kadmin @ldap_plugin_dir@ slave clients \ plugins/kdb/db2 \ plugins/preauth/pkinit \ + plugins/preauth/encrypted_challenge \ appl tests \ config-files gen-manpages BUILDTOP=$(REL)$(C) diff --git a/src/configure.in b/src/configure.in index ef5af2d..b0d3624 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1080,7 +1080,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test plugins/kdb/db2/libdb2/mpool plugins/kdb/db2/libdb2/recno plugins/kdb/db2/libdb2/test - plugins/preauth/cksum_body + plugins/preauth/cksum_body plugins/preauth/encrypted_challenge plugins/preauth/wpse plugins/authdata/greet diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 439d648..db39760 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -910,9 +910,11 @@ error(MIT_DES_KEYSIZE does not equal KRB5_MIT_DES_KEYSIZE) * requested information. It is opaque to the plugin code and can be * expanded in the future as new types of requests are defined which * may require other things to be passed through. */ + struct krb5int_fast_request_state; typedef struct _krb5_preauth_client_rock { krb5_magic magic; - krb5_kdc_rep *as_reply; + krb5_enctype *etype; + struct krb5int_fast_request_state *fast_state; } krb5_preauth_client_rock; /* This structure lets us keep track of all of the modules which are loaded, @@ -2031,7 +2033,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 13 +#define KRB5INT_ACCESS_STRUCT_VERSION 14 #ifndef ANAME_SZ struct ktext; /* from krb.h, for krb524 support */ @@ -2085,6 +2087,16 @@ typedef struct _krb5int_access { krb5_error_code (*asn1_ldap_decode_sequence_of_keys) (krb5_data *in, ldap_seqof_key_data **); + /* Used for encrypted challenge fast factor*/ + krb5_error_code (*encode_enc_data)(const krb5_enc_data *, krb5_data **); + krb5_error_code (*decode_enc_data)(const krb5_data *, krb5_enc_data **); + void (*free_enc_data)(krb5_context, krb5_enc_data *); + krb5_error_code (*encode_enc_ts)(const krb5_pa_enc_ts *, krb5_data **); + krb5_error_code (*decode_enc_ts)(const krb5_data *, krb5_pa_enc_ts **); + void (*free_enc_ts)(krb5_context, krb5_pa_enc_ts *); + krb5_error_code (*encrypt_helper) + (krb5_context, const krb5_keyblock *, krb5_keyusage, const krb5_data *, + krb5_enc_data *); /* * pkinit asn.1 encode/decode functions diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 845cfdf..bf8c29c 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -636,6 +636,8 @@ krb5_error_code KRB5_CALLCONV #define KRB5_KEYUSAGE_FAST_ENC 51 #define KRB5_KEYUSAGE_FAST_REP 52 #define KRB5_KEYUSAGE_FAST_FINISHED 53 +#define KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT 54 +#define KRB5_KEYUSAGE_ENC_CHALLENGE_KDC 55 #define KRB5_KEYUSAGE_FAST_REP 52 krb5_boolean KRB5_CALLCONV krb5_c_valid_enctype diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h index 2429560..e11913e 100644 --- a/src/include/krb5/preauth_plugin.h +++ b/src/include/krb5/preauth_plugin.h @@ -123,11 +123,22 @@ typedef krb5_error_code * information to enable it to process a request. */ enum krb5plugin_preauth_client_request_type { - /* The returned krb5_data item holds the enctype used to encrypt the - * encrypted portion of the AS_REP packet. */ + /* The returned krb5_data item holds the enctype expected to be used to encrypt the + * encrypted portion of the AS_REP packet. When handling a + * PREAUTH_REQUIRED error, this typically comes from etype-info2. + * When handling an AS reply, it is initialized from the AS reply itself.*/ krb5plugin_preauth_client_get_etype = 1, /* Free the data returned from krb5plugin_preauth_client_req_get_etype */ - krb5plugin_preauth_client_free_etype = 2 + krb5plugin_preauth_client_free_etype = 2, + /* The returned krb5_data contains the FAST armor key in a + * krb5_keyblock. Returns success with a NULL data item in the + * krb5_data if the client library supports FAST but is not using it.*/ + krb5plugin_preauth_client_fast_armor = 3, + /* Frees return from KRB5PLUGIN_PREAUTH_CLIENT_FAST_ARMOR. It is + * acceptable to set data to NULL and free the keyblock using + * krb5_free_keyblock; in that case, this frees the krb5_data + * only.*/ +krb5plugin_preauth_client_free_fast_armor = 4, }; typedef krb5_error_code (*preauth_get_client_data_proc)(krb5_context, @@ -326,8 +337,16 @@ enum krb5plugin_preauth_entry_request_type { * 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 -}; + krb5plugin_preauth_request_body = 4, + /* The returned krb5_data contains a krb5_keyblock with the FAST + armor key. The data member is NULL if this method is not part + of a FAST tunnel */ + krb5plugin_preauth_fast_armor = 5, + /* Frees a fast armor key; it is acceptable to set data to NULL + and free the keyblock using krb5_free_keyblock; in that case, + this function simply frees the data*/ + krb5plugin_preauth_free_fast_armor = 6, + }; typedef krb5_error_code (*preauth_get_entry_data_proc)(krb5_context, diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 5b7fbf1..7b590f4 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -151,6 +151,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, status = "error decoding FAST"; goto errout; } + request->kdc_state = state; if (!request->client) { status = "NULL_CLIENT"; errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; @@ -704,6 +705,7 @@ egress: krb5_free_data_contents(kdc_context, &e_data); kdc_free_rstate(state); + request->kdc_state = NULL; krb5_free_kdc_req(kdc_context, request); assert(did_log != 0); return errcode; diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index a80110a..4d7648f 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -668,6 +668,7 @@ get_entry_data(krb5_context context, krb5_keyblock *keys, *mkey_ptr; krb5_key_data *entry_key; krb5_error_code error; + struct kdc_request_state *state = request->kdc_state; switch (type) { case krb5plugin_preauth_entry_request_certificate: @@ -752,6 +753,30 @@ get_entry_data(krb5_context context, } return ASN1_PARSE_ERROR; break; + case krb5plugin_preauth_fast_armor: + ret = calloc(1, sizeof(krb5_data)); + if (ret == NULL) + return ENOMEM; + if (state->armor_key == NULL) { + *result = ret; + return 0; + } + error = krb5_copy_keyblock(context, state->armor_key, &keys); + if (error == 0) { + ret->data = (char *) keys; + ret->length = sizeof(krb5_keyblock); + *result = ret; + return 0; + } + free(ret); + return error; + case krb5plugin_preauth_free_fast_armor: + if ((*result)->data) { + keys = (krb5_keyblock *) (*result)->data; + krb5_free_keyblock(context, keys); + } + free(*result); + return 0; default: break; } diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index be955ae..30a38cd 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -1251,8 +1251,9 @@ krb5_get_init_creds(krb5_context context, goto cleanup; get_data_rock.magic = CLIENT_ROCK_MAGIC; - get_data_rock.as_reply = NULL; - + get_data_rock.etype = &etype; + get_data_rock.fast_state = fast_state; + /* now, loop processing preauth data and talking to the kdc */ for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) { if (request.padata) { @@ -1404,7 +1405,7 @@ krb5_get_init_creds(krb5_context context, if ((ret = sort_krb5_padata_sequence(context, &request.server->realm, local_as_reply->padata))) goto cleanup; - get_data_rock.as_reply = local_as_reply; + etype = local_as_reply->enc_part.enctype; if ((ret = krb5_do_preauth(context, &request, encoded_request_body, encoded_previous_request, diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ccb4af2..4c7dd5e 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -37,6 +37,7 @@ #include "osconf.h" #include <krb5/preauth_plugin.h> #include "int-proto.h" +#include "fast.h" #if !defined(_WIN32) #include <unistd.h> @@ -419,6 +420,7 @@ client_data_proc(krb5_context kcontext, krb5_data **retdata) { krb5_data *ret; + krb5_error_code retval; char *data; if (rock->magic != CLIENT_ROCK_MAGIC) @@ -430,8 +432,6 @@ client_data_proc(krb5_context kcontext, case krb5plugin_preauth_client_get_etype: { krb5_enctype *eptr; - if (rock->as_reply == NULL) - return ENOENT; ret = malloc(sizeof(krb5_data)); if (ret == NULL) return ENOMEM; @@ -443,7 +443,7 @@ client_data_proc(krb5_context kcontext, ret->data = data; ret->length = sizeof(krb5_enctype); eptr = (krb5_enctype *)data; - *eptr = rock->as_reply->enc_part.enctype; + *eptr = *rock->etype; *retdata = ret; return 0; } @@ -457,7 +457,38 @@ client_data_proc(krb5_context kcontext, free(ret); return 0; break; - default: + case krb5plugin_preauth_client_fast_armor: { + krb5_keyblock *key = NULL; + ret = calloc(1, sizeof(krb5_data)); + if (ret == NULL) + return ENOMEM; + retval = 0; + if (rock->fast_state->armor_key) + retval = krb5_copy_keyblock(kcontext, rock->fast_state->armor_key, + &key); + if (retval == 0) { + ret->data = (char *) key; + ret->length = key?sizeof(krb5_keyblock):0; + key = NULL; + } + if (retval == 0) { + *retdata = ret; + ret = NULL; + } + if (ret) + free(ret); + return retval; + } + case krb5plugin_preauth_client_free_fast_armor: + ret = *retdata; + if (ret) { + if (ret->data) + krb5_free_keyblock(kcontext, (krb5_keyblock *) ret->data); + free(ret); + *retdata = NULL; + } + return 0; + default: return EINVAL; } } diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index 1bf171a..bb66568 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -132,6 +132,13 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version) S (encode_krb5_sam_response_2, encode_krb5_sam_response_2), S (encode_krb5_enc_sam_response_enc_2, encode_krb5_enc_sam_response_enc_2), + S (encode_enc_ts, encode_krb5_pa_enc_ts), + S (decode_enc_ts, decode_krb5_pa_enc_ts), + S (encode_enc_data, encode_krb5_enc_data), + S(decode_enc_data, decode_krb5_enc_data), + S(free_enc_ts, krb5_free_pa_enc_ts), + S(free_enc_data, krb5_free_enc_data), + S(encrypt_helper, krb5_encrypt_helper), #if DESIGNATED_INITIALIZERS }; diff --git a/src/plugins/preauth/encrypted_challenge/Makefile.in b/src/plugins/preauth/encrypted_challenge/Makefile.in new file mode 100644 index 0000000..8f6a8a6 --- /dev/null +++ b/src/plugins/preauth/encrypted_challenge/Makefile.in @@ -0,0 +1,41 @@ +thisconfigdir=../../.. +myfulldir=plugins/preauth/encrypted_challenge +mydir=plugins/preauth/encrypted_challenge +BUILDTOP=$(REL)..$(S)..$(S).. +KRB5_RUN_ENV = @KRB5_RUN_ENV@ +KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ; +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) +MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) +DEFS=@DEFS@ + +LOCALINCLUDES = -I../../../include/krb5 -I. + +LIBBASE=encrypted_challenge +LIBMAJOR=0 +LIBMINOR=0 +SO_EXT=.so +RELDIR=../plugins/preauth/encrypted_challenge +# Depends on libk5crypto and libkrb5 +SHLIB_EXPDEPS = \ + $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(TOPLIBD)/libkrb5$(SHLIBEXT) +SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS) + +SHLIB_DIRS=-L$(TOPLIBD) +SHLIB_RDIRS=$(KRB5_LIBDIR) +STOBJLISTS=OBJS.ST +STLIBOBJS=encrypted_challenge_main.o + +SRCS= $(srcdir)/encrypted_challenge_main.c + +all-unix:: $(LIBBASE)$(SO_EXT) +install-unix:: install-libs +clean-unix:: clean-libs clean-libobjs + +clean:: + $(RM) lib$(LIBBASE)$(SO_EXT) + +@libnover_frag@ +@libobj_frag@ + diff --git a/src/plugins/preauth/encrypted_challenge/deps b/src/plugins/preauth/encrypted_challenge/deps new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/plugins/preauth/encrypted_challenge/deps diff --git a/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports b/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports new file mode 100644 index 0000000..98e96c3 --- /dev/null +++ b/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports @@ -0,0 +1,2 @@ +preauthentication_client_1 +preauthentication_server_1 diff --git a/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c new file mode 100644 index 0000000..3fad7cc --- /dev/null +++ b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c @@ -0,0 +1,409 @@ +/* + * plugins/preauth/encrypted_challenge/encrypted_challenge.c + * + * Copyright (C) 2009 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * + * Implement EncryptedChallenge fast factor from draft-ietf-krb-wg-preauth-framework + */ + +#include <k5-int.h> +#include "../fast_factor.h" + +#include <krb5/preauth_plugin.h> + +static int preauth_flags +(krb5_context context, krb5_preauthtype pa_type) +{ + return PA_REAL; +} + +static krb5_error_code process_preauth +(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 *padata, + 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_padata) +{ + krb5_error_code retval = 0; + krb5_enctype enctype = 0; + krb5_keyblock *challenge_key = NULL, *armor_key = NULL; + krb5_data *etype_data = NULL; + krb5int_access kaccess; + + if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) + return 0; + retval = fast_get_armor_key(context, get_data_proc, rock, &armor_key); + if (retval || armor_key == NULL) + return 0; + retval = get_data_proc(context, rock, krb5plugin_preauth_client_get_etype, &etype_data); + if (retval == 0) { + enctype = *((krb5_enctype *)etype_data->data); + if (as_key->length == 0 ||as_key->enctype != enctype) + retval = gak_fct(context, request->client, + enctype, prompter, prompter_data, + salt, s2kparams, + as_key, gak_data); + } + if (padata->length) { + krb5_enc_data *enc = NULL; + krb5_data scratch; + scratch.length = padata->length; + scratch.data = (char *) padata->contents; + if (retval == 0) + retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor", + as_key, "challengelongterm", &challenge_key); + if (retval == 0) + retval =kaccess.decode_enc_data(&scratch, &enc); + scratch.data = NULL; + if (retval == 0) { + scratch.data = malloc(enc->ciphertext.length); + scratch.length = enc->ciphertext.length; + if (scratch.data == NULL) + retval = ENOMEM; + } + if (retval == 0) + retval = krb5_c_decrypt(context, challenge_key, + KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL, + enc, &scratch); +/*Per draft 11 of the preauth framework, the client MAY but + * is not required to actually check the timestamp from the KDC other than + * to confirm it decrypts. This code does not perform that check. + */ + if (scratch.data) + krb5_free_data_contents(context, &scratch); + if (retval == 0) + fast_set_kdc_verified(context, get_data_proc, rock); + if (enc) + kaccess.free_enc_data(context, enc); + } else { /*No padata; we send*/ + krb5_enc_data enc; + krb5_pa_data *pa = NULL; + krb5_pa_data **pa_array = NULL; + krb5_data *encoded_ts = NULL; + krb5_pa_enc_ts ts; + if (retval == 0) + retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); + if (retval == 0) + retval = kaccess.encode_enc_ts(&ts, &encoded_ts); + if (retval == 0) + retval = krb5_c_fx_cf2_simple(context, + armor_key, "clientchallengearmor", + as_key, "challengelongterm", + &challenge_key); + if (retval == 0) + retval = kaccess.encrypt_helper(context, challenge_key, + KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, + encoded_ts, &enc); + if (encoded_ts) + krb5_free_data(context, encoded_ts); + encoded_ts = NULL; + if (retval == 0) { + retval = kaccess.encode_enc_data(&enc, &encoded_ts); + krb5_free_data_contents(context, &enc.ciphertext); + } + if (retval == 0) { + pa = calloc(1, sizeof(krb5_pa_data)); + if (pa == NULL) + retval = ENOMEM; + } + if (retval == 0) { + pa_array = calloc(2, sizeof(krb5_pa_data *)); + if (pa_array == NULL) + retval = ENOMEM; + } + if (retval == 0) { + pa->length = encoded_ts->length; + pa->contents = (unsigned char *) encoded_ts->data; + pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; + free(encoded_ts); + encoded_ts = NULL; + pa_array[0] = pa; + pa = NULL; + *out_padata = pa_array; + pa_array = NULL; + } + if (pa) + free(pa); + if (encoded_ts) + krb5_free_data(context, encoded_ts); + if (pa_array) + free(pa_array); + } + if (challenge_key) + krb5_free_keyblock(context, challenge_key); + if (armor_key) + krb5_free_keyblock(context, armor_key); + if (etype_data != NULL) + get_data_proc(context, rock, krb5plugin_preauth_client_free_etype, + &etype_data); + return retval; +} + + + + +static krb5_error_code kdc_include_padata +(krb5_context context, + krb5_kdc_req *request, + struct _krb5_db_entry_new *client, + struct _krb5_db_entry_new *server, + preauth_get_entry_data_proc get_entry_proc, + void *pa_module_context, + krb5_pa_data *data) +{ + krb5_error_code retval = 0; + krb5_keyblock *armor_key = NULL; + retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key); + if (retval) + return retval; + if (armor_key == 0) + return ENOENT; + krb5_free_keyblock(context, armor_key); + return 0; +} + +static krb5_error_code kdc_verify_preauth +(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 get_entry_proc, + void *pa_module_context, + void **pa_request_context, + krb5_data **e_data, + krb5_authdata ***authz_data) +{ + krb5_error_code retval = 0; + krb5_timestamp now; + krb5_enc_data *enc = NULL; + krb5_data scratch, plain; + krb5_keyblock *armor_key = NULL; + krb5_pa_enc_ts *ts = NULL; + krb5int_access kaccess; + krb5_keyblock *client_keys = NULL; + krb5_data *client_data = NULL; + krb5_keyblock *challenge_key = NULL; + int i; + + plain.data = NULL; + if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) + return 0; + + retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key); + if (retval == 0 &&armor_key == NULL) { + retval = ENOENT; + krb5_set_error_message(context, ENOENT, "Encrypted Challenge used outside of FAST tunnel"); + } + scratch.data = (char *) data->contents; + scratch.length = data->length; + if (retval == 0) + retval = kaccess.decode_enc_data(&scratch, &enc); + if (retval == 0) { + plain.data = malloc(enc->ciphertext.length); + plain.length = enc->ciphertext.length; + if (plain.data == NULL) + retval = ENOMEM; + } + if (retval == 0) + retval = get_entry_proc(context, request, client, + krb5plugin_preauth_keys, &client_data); + if (retval == 0) { + client_keys = (krb5_keyblock *) client_data->data; + for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) { + retval = krb5_c_fx_cf2_simple(context, + armor_key, "clientchallengearmor", + &client_keys[i], "challengelongterm", + &challenge_key); + if (retval == 0) + retval = krb5_c_decrypt(context, challenge_key, + KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, + NULL, enc, &plain); + if (challenge_key) + krb5_free_keyblock(context, challenge_key); + challenge_key = NULL; + if (retval == 0) + break; + /*We failed to decrypt. Try next key*/ + retval = 0; + krb5_free_keyblock_contents(context, &client_keys[i]); + } + if (client_keys[i].enctype == 0) { + retval = KRB5KDC_ERR_PREAUTH_FAILED; + krb5_set_error_message(context, retval, "Incorrect password in encrypted challenge"); + } else { /*not run out of keys*/ + int j; + assert (retval == 0); + for (j = i+1; client_keys[j].enctype; j++) + krb5_free_keyblock_contents(context, &client_keys[j]); + } + + } + if (retval == 0) + retval = kaccess.decode_enc_ts(&plain, &ts); + if (retval == 0) + retval = krb5_timeofday(context, &now); + if (retval == 0) { + if (labs(now-ts->patimestamp) < context->clockskew) { + enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; +/*If this fails, we won't generate a reply to the client. That may + * cause the client to fail, but at this point the KDC has considered + this a success, so the return value is ignored. */ + fast_kdc_replace_reply_key(context, get_entry_proc, request); + krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor", + &client_keys[i], "challengelongterm", + (krb5_keyblock **) pa_request_context); + } else { /*skew*/ + retval = KRB5KRB_AP_ERR_SKEW; + } + } + if (client_keys) { + if (client_keys[i].enctype) + krb5_free_keyblock_contents(context, &client_keys[i]); + krb5_free_data(context, client_data); + } + if (armor_key) + krb5_free_keyblock(context, armor_key); + if (challenge_key) + krb5_free_keyblock(context, challenge_key); + if (plain.data) + free(plain.data); + if (enc) + kaccess.free_enc_data(context, enc); + if (ts) + kaccess.free_enc_ts(context, ts); + return retval; +} + +static krb5_error_code kdc_return_preauth +(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 get_entry_proc, + void *pa_module_context, + void **pa_request_context) +{ + krb5_error_code retval = 0; + krb5_keyblock *challenge_key = *pa_request_context; + krb5_pa_enc_ts ts; + krb5_data *plain = NULL; + krb5_enc_data enc; + krb5_data *encoded = NULL; + krb5_pa_data *pa = NULL; + krb5int_access kaccess; + + if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) + return 0; + if (challenge_key == NULL) + return 0; + * pa_request_context = NULL; /*this function will free the + * challenge key*/ + retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); + if (retval == 0) + retval = kaccess.encode_enc_ts(&ts, &plain); + if (retval == 0) + retval = kaccess.encrypt_helper(context, challenge_key, + KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, + plain, &enc); + if (retval == 0) + retval = kaccess.encode_enc_data(&enc, &encoded); + if (retval == 0) { + pa = calloc(1, sizeof(krb5_pa_data)); + if (pa == NULL) + retval = ENOMEM; + } + if (retval == 0) { + pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; + pa->contents = (unsigned char *) encoded->data; + pa->length = encoded->length; + encoded->data = NULL; + *send_pa = pa; + pa = NULL; + } + if (challenge_key) + krb5_free_keyblock(context, challenge_key); + if (encoded) + krb5_free_data(context, encoded); + if (plain) + krb5_free_data(context, plain); + if (enc.ciphertext.data) + krb5_free_data_contents(context, &enc.ciphertext); + return retval; +} + +static int kdc_preauth_flags +(krb5_context context, krb5_preauthtype patype) +{ + return 0; +} + +krb5_preauthtype supported_pa_types[] = { + KRB5_PADATA_ENCRYPTED_CHALLENGE, 0}; + +struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = { + "Encrypted challenge", + &supported_pa_types[0], +NULL, +NULL, +kdc_preauth_flags, + kdc_include_padata, + kdc_verify_preauth, + kdc_return_preauth, +NULL +}; + +struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = { + "Encrypted Challenge", /* name */ + &supported_pa_types[0], /* pa_type_list */ + NULL, /* enctype_list */ + NULL, /* plugin init function */ + NULL, /* plugin fini function */ + preauth_flags, /* get flags function */ + NULL, /* request init function */ + NULL, /* request fini function */ + process_preauth, /* process function */ + NULL, /* try_again function */ +NULL /* get init creds opt function */ +}; diff --git a/src/plugins/preauth/fast_factor.h b/src/plugins/preauth/fast_factor.h new file mode 100644 index 0000000..4059b28 --- /dev/null +++ b/src/plugins/preauth/fast_factor.h @@ -0,0 +1,53 @@ +/*Returns success with a null armor_key if FAST is available but not in use. +Returns failure if the client library does not support FAST +*/ +static krb5_error_code fast_get_armor_key +(krb5_context context, preauth_get_client_data_proc get_data, + struct _krb5_preauth_client_rock *rock, + krb5_keyblock **armor_key) +{ + krb5_error_code retval = 0; + krb5_data *data; + retval = get_data(context, rock, krb5plugin_preauth_client_fast_armor, &data); + if (retval == 0) { + *armor_key = (krb5_keyblock *) data->data; + data->data = NULL; + get_data(context, rock, krb5plugin_preauth_client_free_fast_armor, + &data); + } + return retval; +} + +static krb5_error_code fast_kdc_get_armor_key +(krb5_context context, preauth_get_entry_data_proc get_entry, + krb5_kdc_req *request,struct _krb5_db_entry_new *client, + krb5_keyblock **armor_key) +{ + krb5_error_code retval; + krb5_data *data; + retval = get_entry(context, request, client, krb5plugin_preauth_fast_armor, + &data); + if (retval == 0) { + *armor_key = (krb5_keyblock *) data->data; + data->data = NULL; + get_entry(context, request, client, + krb5plugin_preauth_free_fast_armor, &data); + } + return retval; + } + + + + static krb5_error_code fast_kdc_replace_reply_key + (krb5_context context, preauth_get_entry_data_proc get_data, + krb5_kdc_req *request) + { + return 0; + } + +static krb5_error_code fast_set_kdc_verified +(krb5_context context, preauth_get_client_data_proc get_data, + struct _krb5_preauth_client_rock *rock) +{ + return 0; +} |