From ca3ec7f3fd59baa0d0eedcb61c7009165ea2730c Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 7 Oct 2011 14:26:25 +0000 Subject: [PATCH] Use built-in modules for encrypted timestamp Break out the encrypted timestamp code from kdc_preauth.c and preauth2.c into built-in modules, allowing admins to disable it and reducing the size of the framework code. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25319 dc483132-0cff-0310-8789-dd5450dbe970 --- doc/admin.texinfo | 3 + .../krb_admins/conf_files/krb5_conf.rst | 3 + src/config-files/krb5.conf.M | 3 + src/kdc/Makefile.in | 2 + src/kdc/kdc_preauth.c | 3 + src/kdc/kdc_preauth_encts.c | 146 ++++++++++++++++++ src/kdc/kdc_util.h | 5 + src/lib/krb5/krb/Makefile.in | 3 + src/lib/krb5/krb/int-proto.h | 4 + src/lib/krb5/krb/preauth2.c | 84 +--------- src/lib/krb5/krb/preauth_encts.c | 136 ++++++++++++++++ 11 files changed, 312 insertions(+), 80 deletions(-) create mode 100644 src/kdc/kdc_preauth_encts.c create mode 100644 src/lib/krb5/krb/preauth_encts.c diff --git a/doc/admin.texinfo b/doc/admin.texinfo index 1930e33f5..cf39f187c 100644 --- a/doc/admin.texinfo +++ b/doc/admin.texinfo @@ -1221,6 +1221,9 @@ This module implements the PKINIT preauthentication mechanism. @itemx encrypted_challenge This module implements the encrypted challenge FAST factor. + +@itemx encrypted_timestamp +This module implements the encrypted timestamp mechanism. @end table @node pkinit client options, Sample krb5.conf File, plugins, krb5.conf diff --git a/doc/rst_source/krb_admins/conf_files/krb5_conf.rst b/doc/rst_source/krb_admins/conf_files/krb5_conf.rst index 5351ae1a6..010fca696 100644 --- a/doc/rst_source/krb_admins/conf_files/krb5_conf.rst +++ b/doc/rst_source/krb_admins/conf_files/krb5_conf.rst @@ -567,6 +567,9 @@ The **clpreauth** and **kdcpreauth** interfaces allow plugin modules to provide **encrypted_challenge** This module implements the encrypted challenge FAST factor. +**encrypted_timestamp** + This module implements the encrypted timestamp mechanism. + PKINIT options ----------------- diff --git a/src/config-files/krb5.conf.M b/src/config-files/krb5.conf.M index a082b8494..af4200c3b 100644 --- a/src/config-files/krb5.conf.M +++ b/src/config-files/krb5.conf.M @@ -804,6 +804,9 @@ This module implements the PKINIT preauthentication mechanism. .IP encrypted_challenge This module implements the encrypted challenge FAST factor. +.IP encrypted_timestamp +This module implements the encrypted timestamp mechanism. + .SH FILES /etc/krb5.conf .SH SEE ALSO diff --git a/src/kdc/Makefile.in b/src/kdc/Makefile.in index 68f1a5b8f..118f8f780 100644 --- a/src/kdc/Makefile.in +++ b/src/kdc/Makefile.in @@ -21,6 +21,7 @@ SRCS= \ $(srcdir)/kdc_util.c \ $(srcdir)/kdc_preauth.c \ $(srcdir)/kdc_preauth_ec.c \ + $(srcdir)/kdc_preauth_encts.c \ $(srcdir)/main.c \ $(srcdir)/policy.c \ $(srcdir)/extern.c \ @@ -36,6 +37,7 @@ OBJS= \ kdc_util.o \ kdc_preauth.o \ kdc_preauth_ec.o \ + kdc_preauth_encts.o \ main.o \ policy.o \ extern.o \ diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 6a04ff2aa..bdcc71b16 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -315,6 +315,9 @@ get_plugin_vtables(krb5_context context, k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, "encrypted_challenge", kdcpreauth_encrypted_challenge_initvt); + k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, + "encrypted_timestamp", + kdcpreauth_encrypted_timestamp_initvt); if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins)) return; diff --git a/src/kdc/kdc_preauth_encts.c b/src/kdc/kdc_preauth_encts.c new file mode 100644 index 000000000..48626d972 --- /dev/null +++ b/src/kdc/kdc_preauth_encts.c @@ -0,0 +1,146 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* kdc/kdc_preauth_encts.c - Encrypted timestamp kdcpreauth module */ +/* + * Copyright (C) 1995, 2003, 2007, 2011 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. + */ + +#include +#include +#include "kdc_util.h" + +static krb5_error_code +enc_ts_get(krb5_context context, krb5_kdc_req *request, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, krb5_pa_data *data) +{ + krb5_keyblock *armor_key = cb->fast_armor(context, rock); + + return (armor_key != NULL) ? ENOENT : 0; +} + +static void +enc_ts_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + krb5_pa_enc_ts * pa_enc = 0; + krb5_error_code retval; + krb5_data scratch; + krb5_data enc_ts_data; + krb5_enc_data *enc_data = 0; + krb5_keyblock key; + krb5_key_data * client_key; + krb5_int32 start; + krb5_timestamp timenow; + krb5_error_code decrypt_err = 0; + + scratch.data = (char *)pa->contents; + scratch.length = pa->length; + + enc_ts_data.data = 0; + + if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0) + goto cleanup; + + enc_ts_data.length = enc_data->ciphertext.length; + if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL) + goto cleanup; + + start = 0; + decrypt_err = 0; + while (1) { + if ((retval = krb5_dbe_search_enctype(context, rock->client, + &start, enc_data->enctype, + -1, 0, &client_key))) + goto cleanup; + + if ((retval = krb5_dbe_decrypt_key_data(context, NULL, client_key, + &key, NULL))) + goto cleanup; + + key.enctype = enc_data->enctype; + + retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, + 0, enc_data, &enc_ts_data); + krb5_free_keyblock_contents(context, &key); + if (retval == 0) + break; + else + decrypt_err = retval; + } + + if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0) + goto cleanup; + + if ((retval = krb5_timeofday(context, &timenow)) != 0) + goto cleanup; + + if (labs(timenow - pa_enc->patimestamp) > context->clockskew) { + retval = KRB5KRB_AP_ERR_SKEW; + goto cleanup; + } + + setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH); + + retval = 0; + +cleanup: + if (enc_data) { + krb5_free_data_contents(context, &enc_data->ciphertext); + free(enc_data); + } + krb5_free_data_contents(context, &enc_ts_data); + if (pa_enc) + free(pa_enc); + /* + * If we get NO_MATCHING_KEY and decryption previously failed, and + * we failed to find any other keys of the correct enctype after + * that failed decryption, it probably means that the password was + * incorrect. + */ + if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0) + retval = decrypt_err; + + (*respond)(arg, retval, NULL, NULL, NULL); +} + +static krb5_preauthtype enc_ts_types[] = { + KRB5_PADATA_ENC_TIMESTAMP, 0 }; + +krb5_error_code +kdcpreauth_encrypted_timestamp_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable) +{ + krb5_kdcpreauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_kdcpreauth_vtable)vtable; + vt->name = "encrypted_timestamp"; + vt->pa_type_list = enc_ts_types; + vt->edata = enc_ts_get; + vt->verify = enc_ts_verify; + return 0; +} diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 6d91822ff..e33f606b8 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -205,6 +205,11 @@ krb5_error_code kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); +/* kdc_preauth_enctsc.c */ +krb5_error_code +kdcpreauth_encrypted_timestamp_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); + /* kdc_authdata.c */ krb5_error_code load_authdata_plugins(krb5_context context); diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index ddef9e29a..fe55c24ee 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -78,6 +78,7 @@ STLIBOBJS= \ pr_to_salt.o \ preauth2.o \ preauth_ec.o \ + preauth_encts.o \ gic_opt_set_pa.o \ princ_comp.o \ privsafe.o \ @@ -182,6 +183,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)pr_to_salt.$(OBJEXT) \ $(OUTPRE)preauth2.$(OBJEXT) \ $(OUTPRE)preauth_ec.$(OBJEXT) \ + $(OUTPRE)preauth_encts.$(OBJEXT) \ $(OUTPRE)gic_opt_set_pa.$(OBJEXT) \ $(OUTPRE)princ_comp.$(OBJEXT) \ $(OUTPRE)privsafe.$(OBJEXT) \ @@ -286,6 +288,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/pr_to_salt.c \ $(srcdir)/preauth2.c \ $(srcdir)/preauth_ec.c \ + $(srcdir)/preauth_encts.c \ $(srcdir)/gic_opt_set_pa.c \ $(srcdir)/princ_comp.c \ $(srcdir)/privsafe.c \ diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 7aebdb162..4e2d1deb2 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -57,6 +57,10 @@ krb5_error_code clpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); +krb5_error_code +clpreauth_encrypted_timestamp_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable); + krb5_error_code krb5int_construct_matching_creds(krb5_context context, krb5_flags options, krb5_creds *in_creds, krb5_creds *mcreds, diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index 8c43938ef..f2ead9361 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -120,12 +120,15 @@ krb5_init_preauth_context(krb5_context kcontext) if (kcontext->preauth_context != NULL) return; - /* Auto-register encrypted challenge and (if possible) pkinit. */ + /* Auto-register built-in modules. */ k5_plugin_register_dyn(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "pkinit", "preauth"); k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "encrypted_challenge", clpreauth_encrypted_challenge_initvt); + k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH, + "encrypted_timestamp", + clpreauth_encrypted_timestamp_initvt); /* Get all available clpreauth vtables. */ if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins)) @@ -561,80 +564,6 @@ pa_fx_cookie(krb5_context context, krb5_kdc_req *request, return 0; } -static krb5_error_code -pa_enc_timestamp(krb5_context context, krb5_kdc_req *request, - krb5_pa_data *in_padata, krb5_pa_data **out_padata, - krb5_data *salt, krb5_data *s2kparams, 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_error_code ret; - krb5_pa_enc_ts pa_enc; - krb5_data *tmp; - krb5_enc_data enc_data; - krb5_pa_data *pa; - - if (as_key->length == 0) { -#ifdef DEBUG - fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__, - salt->length); - if ((int) salt->length > 0) - fprintf (stderr, " '%.*s'", salt->length, salt->data); - fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n", - *etype, request->ktype[0]); -#endif - if ((ret = ((*gak_fct)(context, request->client, - *etype ? *etype : request->ktype[0], - prompter, prompter_data, - salt, s2kparams, as_key, gak_data)))) - return(ret); - TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key); - } - - /* now get the time of day, and encrypt it accordingly */ - - if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec))) - return(ret); - - if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp))) - return(ret); - - ret = krb5_encrypt_helper(context, as_key, - KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, - tmp, &enc_data); - TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec, - tmp, &enc_data.ciphertext); - - krb5_free_data(context, tmp); - - if (ret) - return(ret); - - ret = encode_krb5_enc_data(&enc_data, &tmp); - - free(enc_data.ciphertext.data); - - if (ret) - return(ret); - - if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) { - krb5_free_data(context, tmp); - return(ENOMEM); - } - - pa->magic = KV5M_PA_DATA; - pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP; - pa->length = tmp->length; - pa->contents = (krb5_octet *) tmp->data; - - *out_padata = pa; - - free(tmp); - - return(0); -} - #if APPLE_PKINIT /* * PKINIT. One function to generate AS-REQ, one to parse AS-REP @@ -1386,11 +1315,6 @@ static const pa_types_t pa_types[] = { PA_REAL, }, #endif /* APPLE_PKINIT */ - { - KRB5_PADATA_ENC_TIMESTAMP, - pa_enc_timestamp, - PA_REAL, - }, { KRB5_PADATA_SAM_CHALLENGE_2, pa_sam_2, diff --git a/src/lib/krb5/krb/preauth_encts.c b/src/lib/krb5/krb/preauth_encts.c new file mode 100644 index 000000000..6e3268603 --- /dev/null +++ b/src/lib/krb5/krb/preauth_encts.c @@ -0,0 +1,136 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/preauth_encts.c - Encrypted timestamp clpreauth module */ +/* + * Copyright 1995, 2003, 2008, 2011 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. + * + */ + +#include +#include +#include "int-proto.h" + +static int +encts_flags(krb5_context context, krb5_preauthtype pa_type) +{ + return PA_REAL; +} + +static krb5_error_code +encts_process(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_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, + krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data, + krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, + krb5_pa_data ***out_padata) +{ + krb5_error_code ret; + krb5_pa_enc_ts pa_enc; + krb5_data *ts = NULL, *enc_ts = NULL; + krb5_enc_data enc_data; + krb5_pa_data **pa = NULL; + krb5_enctype etype = cb->get_etype(context, rock); + + enc_data.ciphertext = empty_data(); + + if (as_key->length == 0) { +#ifdef DEBUG + fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__, + salt->length); + if ((int) salt->length > 0) + fprintf (stderr, " '%.*s'", salt->length, salt->data); + fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n", + etype, request->ktype[0]); +#endif + ret = (*gak_fct)(context, request->client, etype, prompter, + prompter_data, salt, s2kparams, as_key, gak_data); + if (ret) + goto cleanup; + TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key); + } + + /* now get the time of day, and encrypt it accordingly */ + ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec); + if (ret) + goto cleanup; + + ret = encode_krb5_pa_enc_ts(&pa_enc, &ts); + if (ret) + goto cleanup; + + ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, + ts, &enc_data); + if (ret) + goto cleanup; + TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec, + ts, &enc_data.ciphertext); + + ret = encode_krb5_enc_data(&enc_data, &enc_ts); + if (ret) + goto cleanup; + + pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret); + if (pa == NULL) + goto cleanup; + + pa[0] = k5alloc(sizeof(krb5_pa_data), &ret); + if (pa[0] == NULL) + goto cleanup; + + pa[0]->magic = KV5M_PA_DATA; + pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP; + pa[0]->length = enc_ts->length; + pa[0]->contents = (krb5_octet *) enc_ts->data; + enc_ts->data = NULL; + pa[1] = NULL; + *out_padata = pa; + pa = NULL; + +cleanup: + krb5_free_data(context, ts); + krb5_free_data(context, enc_ts); + free(enc_data.ciphertext.data); + free(pa); + return ret; +} + +static krb5_preauthtype encts_pa_types[] = { + KRB5_PADATA_ENC_TIMESTAMP, 0}; + +krb5_error_code +clpreauth_encrypted_timestamp_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable) +{ + krb5_clpreauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_clpreauth_vtable)vtable; + vt->name = "encrypted_timestamp"; + vt->pa_type_list = encts_pa_types; + vt->flags = encts_flags; + vt->process = encts_process; + return 0; +} -- 2.26.2