diff options
| author | Sam Hartman <hartmans@mit.edu> | 2009-03-31 17:00:41 +0000 |
|---|---|---|
| committer | Sam Hartman <hartmans@mit.edu> | 2009-03-31 17:00:41 +0000 |
| commit | d1384be39be11423bd05b88ec444733361fc1467 (patch) | |
| tree | f577c2d27f9f96c1c3633c740bbf02b606534650 /src/lib | |
| parent | 22810910e3c834ee0bc66d0c96369c43e780a2bb (diff) | |
Implement FAST from draft-ietf-krb-wg-preauth-framework
Merge fast branch at 22146 onto trunk
Implement the kerberos pre-authentication framework FAST feature per
Projects/FAST on the wiki.
ticket: 6436
Target_Version: 1.7
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22149 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/krb5/asn.1/asn1_k_decode.c | 51 | ||||
| -rw-r--r-- | src/lib/krb5/asn.1/asn1_k_decode.h | 12 | ||||
| -rw-r--r-- | src/lib/krb5/asn.1/asn1_k_encode.c | 88 | ||||
| -rw-r--r-- | src/lib/krb5/asn.1/krb5_decode.c | 93 | ||||
| -rw-r--r-- | src/lib/krb5/error_tables/krb5_err.et | 3 | ||||
| -rw-r--r-- | src/lib/krb5/error_tables/kv5m_err.et | 4 | ||||
| -rw-r--r-- | src/lib/krb5/krb/Makefile.in | 3 | ||||
| -rw-r--r-- | src/lib/krb5/krb/fast.c | 499 | ||||
| -rw-r--r-- | src/lib/krb5/krb/fast.h | 77 | ||||
| -rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 65 | ||||
| -rw-r--r-- | src/lib/krb5/krb/gic_opt.c | 20 | ||||
| -rw-r--r-- | src/lib/krb5/krb/kfree.c | 62 | ||||
| -rw-r--r-- | src/lib/krb5/krb/preauth2.c | 39 | ||||
| -rw-r--r-- | src/lib/krb5/libkrb5.exports | 11 | ||||
| -rw-r--r-- | src/lib/krb5/os/accessor.c | 7 |
15 files changed, 1013 insertions, 21 deletions
diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c index 25cc4cc62..c6857fe60 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.c +++ b/src/lib/krb5/asn.1/asn1_k_decode.c @@ -1625,6 +1625,57 @@ error_out: return retval; } +asn1_error_code asn1_decode_fast_armor +(asn1buf *buf, krb5_fast_armor *val) +{ + setup(); + val->armor_value.data = NULL; + {begin_structure(); + get_field(val->armor_type, 0, asn1_decode_int32); + get_lenfield(val->armor_value.length, val->armor_value.data, + 1, asn1_decode_charstring); + end_structure(); + } + return 0; + error_out: + krb5_free_data_contents( NULL, &val->armor_value); + return retval; +} + +asn1_error_code asn1_decode_fast_armor_ptr +(asn1buf *buf, krb5_fast_armor **valptr) +{ + decode_ptr(krb5_fast_armor *, asn1_decode_fast_armor); +} + +asn1_error_code asn1_decode_fast_finished +(asn1buf *buf, krb5_fast_finished *val) +{ + setup(); + val->client = NULL; + val->ticket_checksum.contents = NULL; + {begin_structure(); + get_field(val->timestamp, 0, asn1_decode_kerberos_time); + get_field(val->usec, 1, asn1_decode_int32); + alloc_field(val->client); + get_field(val->client, 2, asn1_decode_realm); + get_field(val->client, 3, asn1_decode_principal_name); + get_field(val->ticket_checksum, 4, asn1_decode_checksum); + end_structure(); + } + return 0; + error_out: + krb5_free_principal(NULL, val->client); + krb5_free_checksum_contents( NULL, &val->ticket_checksum); + return retval; +} +asn1_error_code asn1_decode_fast_finished_ptr +(asn1buf *buf, krb5_fast_finished **valptr) +{ + decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished); +} + + #ifndef DISABLE_PKINIT /* PKINIT */ diff --git a/src/lib/krb5/asn.1/asn1_k_decode.h b/src/lib/krb5/asn.1/asn1_k_decode.h index f258f65c4..7444443ba 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.h +++ b/src/lib/krb5/asn.1/asn1_k_decode.h @@ -266,4 +266,16 @@ asn1_error_code asn1_decode_pa_for_user asn1_error_code asn1_decode_pa_pac_req (asn1buf *buf, krb5_pa_pac_req *val); +asn1_error_code asn1_decode_fast_armor +(asn1buf *buf, krb5_fast_armor *val); + +asn1_error_code asn1_decode_fast_armor_ptr +(asn1buf *buf, krb5_fast_armor **val); + +asn1_error_code asn1_decode_fast_finished +(asn1buf *buf, krb5_fast_finished *val); + +asn1_error_code asn1_decode_fast_finished_ptr +(asn1buf *buf, krb5_fast_finished **val); + #endif diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index 4790b57f1..53ce7fee1 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -338,6 +338,8 @@ asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *val, DEFFNXTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body); /* end ugly hack */ +DEFPTRTYPE(ptr_kdc_req_body,kdc_req_body); + static const struct field_info transited_fields[] = { FIELDOF_NORM(krb5_transited, octet, tr_type, 0), FIELDOF_NORM(krb5_transited, ostring_data, tr_contents, 1), @@ -1177,6 +1179,88 @@ DEFSEQTYPE(pa_pac_request, krb5_pa_pac_req, pa_pac_request_fields, 0); DEFFIELDTYPE(etype_list, krb5_etype_list, FIELDOF_SEQOF_INT32(krb5_etype_list, int32_ptr, etypes, length, -1)); +/* draft-ietf-krb-wg-preauth-framework-09 */ +static const struct field_info fast_armor_fields[] = { + FIELDOF_NORM(krb5_fast_armor, int32, armor_type, 0), + FIELDOF_NORM( krb5_fast_armor, ostring_data, armor_value, 1), +}; + +DEFSEQTYPE( fast_armor, krb5_fast_armor, fast_armor_fields, 0); +DEFPTRTYPE( ptr_fast_armor, fast_armor); + +static const struct field_info fast_armored_req_fields[] = { + FIELDOF_OPT( krb5_fast_armored_req, ptr_fast_armor, armor, 0, 0), + FIELDOF_NORM( krb5_fast_armored_req, checksum, req_checksum, 1), + FIELDOF_NORM( krb5_fast_armored_req, encrypted_data, enc_part, 2), +}; + +static unsigned int fast_armored_req_optional (const void *p) { + const krb5_fast_armored_req *val = p; + unsigned int optional = 0; + if (val->armor) + optional |= (1u)<<0; + return optional; +} + +DEFSEQTYPE( fast_armored_req, krb5_fast_armored_req, fast_armored_req_fields, fast_armored_req_optional); +DEFFIELDTYPE( pa_fx_fast_request, krb5_fast_armored_req, + FIELDOF_ENCODEAS( krb5_fast_armored_req, fast_armored_req, 0)); + +DEFFIELDTYPE(fast_req_padata, krb5_kdc_req, + FIELDOF_NORM(krb5_kdc_req, ptr_seqof_pa_data, padata, -1)); +DEFPTRTYPE(ptr_fast_req_padata, fast_req_padata); + +static const struct field_info fast_req_fields[] = { + FIELDOF_NORM(krb5_fast_req, int32, fast_options, 0), + FIELDOF_NORM( krb5_fast_req, ptr_fast_req_padata, req_body, 1), + FIELDOF_NORM( krb5_fast_req, ptr_kdc_req_body, req_body, 2), +}; + +DEFSEQTYPE(fast_req, krb5_fast_req, fast_req_fields, 0); + + +static const struct field_info fast_finished_fields[] = { + FIELDOF_NORM( krb5_fast_finished, kerberos_time, timestamp, 0), + FIELDOF_NORM( krb5_fast_finished, int32, usec, 1), + FIELDOF_NORM( krb5_fast_finished, realm_of_principal, client, 2), + FIELDOF_NORM(krb5_fast_finished, principal, client, 3), + FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 4), +}; + +DEFSEQTYPE( fast_finished, krb5_fast_finished, fast_finished_fields, 0); + +DEFPTRTYPE( ptr_fast_finished, fast_finished); + +static const struct field_info fast_response_fields[] = { + FIELDOF_NORM(krb5_fast_response, ptr_seqof_pa_data, padata, 0), + FIELDOF_OPT( krb5_fast_response, ptr_encryption_key, rep_key, 1, 1), + FIELDOF_OPT( krb5_fast_response, ptr_fast_finished, finished, 2, 2), + FIELDOF_NORM(krb5_fast_response, int32, nonce, 3), +}; + +static unsigned int fast_response_optional (const void *p) +{ + unsigned int optional = 0; + const krb5_fast_response *val = p; + if (val->rep_key) + optional |= (1u <<1); + if (val->finished) + optional |= (1u<<2); + return optional; +} +DEFSEQTYPE( fast_response, krb5_fast_response, fast_response_fields, fast_response_optional); + +static const struct field_info fast_rep_fields[] = { + FIELDOF_ENCODEAS(krb5_enc_data, encrypted_data, 0), +}; +DEFSEQTYPE(fast_rep, krb5_enc_data, fast_rep_fields, 0); + +DEFFIELDTYPE(pa_fx_fast_reply, krb5_enc_data, + FIELDOF_ENCODEAS(krb5_enc_data, fast_rep, 0)); + + + + /* Exported complete encoders -- these produce a krb5_data with the encoding in the correct byte order. */ @@ -1243,6 +1327,10 @@ MAKE_FULL_ENCODER(encode_krb5_pa_svr_referral_data, pa_svr_referral_data); MAKE_FULL_ENCODER(encode_krb5_pa_server_referral_data, pa_server_referral_data); MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list); +MAKE_FULL_ENCODER(encode_krb5_pa_fx_fast_request, pa_fx_fast_request); +MAKE_FULL_ENCODER( encode_krb5_fast_req, fast_req); +MAKE_FULL_ENCODER( encode_krb5_pa_fx_fast_reply, pa_fx_fast_reply); +MAKE_FULL_ENCODER(encode_krb5_fast_response, fast_response); diff --git a/src/lib/krb5/asn.1/krb5_decode.c b/src/lib/krb5/asn.1/krb5_decode.c index b118c453c..32d60915d 100644 --- a/src/lib/krb5/asn.1/krb5_decode.c +++ b/src/lib/krb5/asn.1/krb5_decode.c @@ -94,9 +94,9 @@ if ((var) == NULL) clean_return(ENOMEM) /* process a structure *******************************************/ /* decode an explicit tag and place the number in tagnum */ -#define next_tag() \ +#define next_tag_from_buf(buf) \ { taginfo t2; \ - retval = asn1_get_tag_2(&subbuf, &t2); \ + retval = asn1_get_tag_2(&(buf), &t2); \ if (retval) clean_return(retval); \ asn1class = t2.asn1class; \ construction = t2.construction; \ @@ -104,6 +104,8 @@ if ((var) == NULL) clean_return(ENOMEM) indef = t2.indef; \ taglen = t2.length; \ } +#define next_tag() next_tag_from_buf(subbuf) + static asn1_error_code asn1_get_eoc_tag (asn1buf *buf) @@ -518,6 +520,7 @@ decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr) clear_field(rep,authorization_data.ciphertext.data); clear_field(rep,unenc_authdata); clear_field(rep,second_ticket); + clear_field(rep, kdc_state); check_apptag(10); retval = asn1_decode_kdc_req(&buf,rep); @@ -545,6 +548,7 @@ decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **repptr) clear_field(rep,authorization_data.ciphertext.data); clear_field(rep,unenc_authdata); clear_field(rep,second_ticket); + clear_field(rep, kdc_state); check_apptag(12); retval = asn1_decode_kdc_req(&buf,rep); @@ -1080,6 +1084,91 @@ decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **repptr) cleanup(free); } +krb5_error_code decode_krb5_pa_fx_fast_request +(const krb5_data *code, krb5_fast_armored_req **repptr) +{ + setup(krb5_fast_armored_req *); + alloc_field(rep); + clear_field(rep, armor); + { + int indef; + unsigned int taglen; + next_tag_from_buf(buf); + if (tagnum != 0) + clean_return(ASN1_BAD_ID); + } + {begin_structure(); + opt_field(rep->armor, 0, asn1_decode_fast_armor_ptr); + get_field(rep->req_checksum, 1, asn1_decode_checksum); + get_field(rep->enc_part, 2, asn1_decode_encrypted_data); + end_structure();} + rep->magic = KV5M_FAST_ARMORED_REQ; + cleanup(free); +} + +krb5_error_code decode_krb5_fast_req +(const krb5_data *code, krb5_fast_req **repptr) +{ + setup(krb5_fast_req *); + alloc_field(rep); + alloc_field(rep->req_body); + clear_field(rep, req_body->padata); + {begin_structure(); + get_field(rep->fast_options, 0, asn1_decode_int32); + opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data); + get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body); + end_structure(); } + rep->magic = KV5M_FAST_REQ; + cleanup_manual(); + error_out: + if (rep) { + if (rep->req_body) + krb5_free_kdc_req(0, rep->req_body); + free(rep); + } + return retval; +} + +krb5_error_code decode_krb5_fast_response +(const krb5_data *code, krb5_fast_response **repptr) +{ + setup(krb5_fast_response *); + + alloc_field(rep); + clear_field(rep, finished); + clear_field(rep, padata); + clear_field(rep,rep_key); + {begin_structure(); + get_field(rep->padata, 0, asn1_decode_sequence_of_pa_data); + opt_field(rep->rep_key, 1, asn1_decode_encryption_key_ptr); + opt_field(rep->finished, 2, asn1_decode_fast_finished_ptr); + get_field(rep->nonce, 3, asn1_decode_int32); + end_structure(); } + rep->magic = KV5M_FAST_RESPONSE; + cleanup(free); +} + +krb5_error_code decode_krb5_pa_fx_fast_reply +(const krb5_data *code, krb5_enc_data **repptr) +{ + setup(krb5_enc_data *); + alloc_field(rep); + { + int indef; + unsigned int taglen; + next_tag_from_buf(buf); + if (tagnum != 0) + clean_return(ASN1_BAD_ID); + } + {begin_structure(); + get_field(*rep, 0, asn1_decode_encrypted_data); + end_structure(); + } + + cleanup(free); +} + + #ifndef DISABLE_PKINIT krb5_error_code decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr) diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 71db24ee6..5698f1e4a 100644 --- a/src/lib/krb5/error_tables/krb5_err.et +++ b/src/lib/krb5/error_tables/krb5_err.et @@ -134,7 +134,7 @@ error_code KRB5PLACEHOLD_89, "KRB5 error code 89" error_code KRB5PLACEHOLD_90, "KRB5 error code 90" error_code KRB5PLACEHOLD_91, "KRB5 error code 91" error_code KRB5PLACEHOLD_92, "KRB5 error code 92" -error_code KRB5PLACEHOLD_93, "KRB5 error code 93" +error_code KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION, "An unsupported critical FAST option was requested" error_code KRB5PLACEHOLD_94, "KRB5 error code 94" error_code KRB5PLACEHOLD_95, "KRB5 error code 95" error_code KRB5PLACEHOLD_96, "KRB5 error code 96" @@ -347,4 +347,5 @@ error_code KRB5_PLUGIN_NO_HANDLE, "Supplied data not handled by this plugin" error_code KRB5_PLUGIN_OP_NOTSUPP, "Plugin does not support the operaton" error_code KRB5_ERR_INVALID_UTF8, "Invalid UTF-8 string" +error_code KRB5_ERR_FAST_REQUIRED, "FAST protected pre-authentication required but not supported by KDC" end diff --git a/src/lib/krb5/error_tables/kv5m_err.et b/src/lib/krb5/error_tables/kv5m_err.et index 1b79de252..d68398cf9 100644 --- a/src/lib/krb5/error_tables/kv5m_err.et +++ b/src/lib/krb5/error_tables/kv5m_err.et @@ -86,5 +86,7 @@ error_code KV5M_PREDICTED_SAM_RESPONSE, "Bad magic number for krb5_predicted_sam error_code KV5M_PASSWD_PHRASE_ELEMENT, "Bad magic number for passwd_phrase_element" error_code KV5M_GSS_OID, "Bad magic number for GSSAPI OID" error_code KV5M_GSS_QUEUE, "Bad magic number for GSSAPI QUEUE" - +error_code KV5M_FAST_ARMORED_REQ, "Bad magic number for fast armored request" +error_code KV5M_FAST_REQ, "Bad magic number for FAST request" +error_code KV5M_FAST_RESPONSE, "Bad magic number for FAST response" end diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 23b27e527..acc18f6f4 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -40,6 +40,7 @@ STLIBOBJS= \ enc_helper.o \ encode_kdc.o \ encrypt_tk.o \ + fast.o \ free_rtree.o \ fwd_tgt.o \ gc_frm_kdc.o \ @@ -127,6 +128,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)enc_helper.$(OBJEXT) \ $(OUTPRE)encode_kdc.$(OBJEXT) \ $(OUTPRE)encrypt_tk.$(OBJEXT) \ + $(OUTPRE)fast.$(OBJEXT) \ $(OUTPRE)free_rtree.$(OBJEXT) \ $(OUTPRE)fwd_tgt.$(OBJEXT) \ $(OUTPRE)gc_frm_kdc.$(OBJEXT) \ @@ -215,6 +217,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/enc_helper.c \ $(srcdir)/encode_kdc.c \ $(srcdir)/encrypt_tk.c \ + $(srcdir)/fast.c \ $(srcdir)/free_rtree.c \ $(srcdir)/fwd_tgt.c \ $(srcdir)/gc_frm_kdc.c \ diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c new file mode 100644 index 000000000..e9f54be78 --- /dev/null +++ b/src/lib/krb5/krb/fast.c @@ -0,0 +1,499 @@ +/* + * lib/krb5/krb/fast.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. + * + * + * + */ + +#include <k5-int.h> + +/* + * It is possible to support sending a request that includes both a + * FAST and normal version. This would complicate the + * pre-authentication logic significantly. You would need to maintain + * two contexts, one for FAST and one for normal use. In adition, you + * would need to manage the security issues surrounding downgrades. + * However trying FAST at all requires an armor key. Generally in + * obtaining the armor key, the client learns enough to know that FAST + * is supported. If not, the client can see FAST in the + * preauth_required error's padata and retry with FAST. So, this + * implementation does not support FAST+normal. + * + * We store the outer version of the request to use . The caller + * stores the inner version. We handle the encoding of the request + * body (and request) and provide encoded request bodies for the + * caller to use as these may be used for checksums. In the AS case + * we also evaluate whether to continue a conversation as one of the + * important questions there is the presence of a cookie. + */ +#include "fast.h" +#include "int-proto.h" + + +static krb5_error_code fast_armor_ap_request +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_ccache ccache, krb5_data *target_realm) +{ + krb5_error_code retval = 0; + krb5_creds creds, *out_creds = NULL; + krb5_auth_context authcontext = NULL; + krb5_data encoded_authenticator; + krb5_fast_armor *armor = NULL; + krb5_keyblock *subkey = NULL, *armor_key = NULL; + encoded_authenticator.data = NULL; + memset(&creds, 0, sizeof(creds)); + retval = krb5_tgtname(context, target_realm, target_realm, &creds.server); + if (retval ==0) + retval = krb5_cc_get_principal(context, ccache, &creds.client); + if (retval == 0) + retval = krb5_get_credentials(context, 0, ccache, &creds, &out_creds); + if (retval == 0) + retval = krb5_mk_req_extended(context, &authcontext, AP_OPTS_USE_SUBKEY, NULL /*data*/, + out_creds, &encoded_authenticator); + if (retval == 0) + retval = krb5_auth_con_getsendsubkey(context, authcontext, &subkey); + if (retval == 0) + retval = krb5_c_fx_cf2_simple(context, subkey, "subkeyarmor", + &out_creds->keyblock, "ticketarmor", &armor_key); + if (retval == 0) { + armor = calloc(1, sizeof(krb5_fast_armor)); + if (armor == NULL) + retval = ENOMEM; + } + if (retval == 0) { + armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST; + armor->armor_value = encoded_authenticator; + encoded_authenticator.data = NULL; + encoded_authenticator.length = 0; + state->armor = armor; + armor = NULL; + state->armor_key = armor_key; + armor_key = NULL; + } + krb5_free_keyblock(context, armor_key); + krb5_free_keyblock(context, subkey); + if (out_creds) + krb5_free_creds(context, out_creds); + krb5_free_cred_contents(context, &creds); + if (encoded_authenticator.data) + krb5_free_data_contents(context, &encoded_authenticator); + krb5_auth_con_free(context, authcontext); + return retval; +} + +krb5_error_code +krb5int_fast_prep_req_body(krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_req *request, krb5_data **encoded_request_body) +{ + krb5_error_code retval = 0; + krb5_data *local_encoded_request_body = NULL; + assert(state != NULL); + *encoded_request_body = NULL; + if (state->armor_key == NULL) { + return encode_krb5_kdc_req_body(request, encoded_request_body); + } + state->fast_outer_request = *request; + state->fast_outer_request.padata = NULL; + if (retval == 0) + retval = encode_krb5_kdc_req_body(&state->fast_outer_request, + &local_encoded_request_body); + if (retval == 0) { + *encoded_request_body = local_encoded_request_body; + local_encoded_request_body = NULL; + } + if (local_encoded_request_body != NULL) + krb5_free_data(context, local_encoded_request_body); + return retval; +} + +krb5_error_code krb5int_fast_as_armor +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_gic_opt_ext *opte, + krb5_kdc_req *request) +{ + krb5_error_code retval = 0; + krb5_ccache ccache = NULL; + krb5_clear_error_message(context); + if (opte->opt_private->fast_ccache_name) { + retval = krb5_cc_resolve(context, opte->opt_private->fast_ccache_name, + &ccache); + if (retval==0) + retval = fast_armor_ap_request(context, state, ccache, + krb5_princ_realm(context, request->server)); + if (retval != 0) { + const char * errmsg; + errmsg = krb5_get_error_message(context, retval); + if (errmsg) { + krb5_set_error_message(context, retval, "%s constructing AP-REQ armor", errmsg); + krb5_free_error_message(context, errmsg); + } + } + } + if (ccache) + krb5_cc_close(context, ccache); + return retval; +} + + +krb5_error_code +krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_req *request, + const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder, + krb5_data **encoded_request) +{ + krb5_error_code retval = 0; + krb5_pa_data *pa_array[2]; + krb5_pa_data pa[2]; + krb5_fast_req fast_req; + krb5_fast_armored_req *armored_req = NULL; + krb5_data *encoded_fast_req = NULL; + krb5_data *encoded_armored_req = NULL; + krb5_data *local_encoded_result = NULL; + krb5_cksumtype cksumtype; + krb5_data random_data; + char random_buf[4]; + + + assert(state != NULL); + assert(state->fast_outer_request.padata == NULL); + memset(pa_array, 0, sizeof pa_array); + if (state->armor_key == NULL) { + return encoder(request, encoded_request); + } +/* Fill in a fresh random nonce for each inner request*/ + random_data.length = 4; + random_data.data = (char *)random_buf; + retval = krb5_c_random_make_octets(context, &random_data); + if (retval == 0) { + request->nonce = 0x7fffffff & load_32_n(random_buf); + state->nonce = request->nonce; + } + fast_req.req_body = request; + if (fast_req.req_body->padata == NULL) { + fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *)); + if (fast_req.req_body->padata == NULL) + retval = ENOMEM; + } + fast_req.fast_options = state->fast_options; + if (retval == 0) + retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req); + if (retval == 0) { + armored_req = calloc(1, sizeof(krb5_fast_armored_req)); + if (armored_req == NULL) + retval = ENOMEM; + } + if (retval == 0) + armored_req->armor = state->armor; + if (retval == 0) + retval = krb5int_c_mandatory_cksumtype(context, state->armor_key->enctype, + &cksumtype); + if (retval ==0) + retval = krb5_c_make_checksum(context, cksumtype, state->armor_key, + KRB5_KEYUSAGE_FAST_REQ_CHKSUM, to_be_checksummed, + &armored_req->req_checksum); + if (retval == 0) + retval = krb5_encrypt_helper(context, state->armor_key, + KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req, + &armored_req->enc_part); + if (retval == 0) + retval = encode_krb5_pa_fx_fast_request(armored_req, &encoded_armored_req); + if (retval==0) { + pa[0].pa_type = KRB5_PADATA_FX_FAST; + pa[0].contents = (unsigned char *) encoded_armored_req->data; + pa[0].length = encoded_armored_req->length; + pa_array[0] = &pa[0]; + } + state->fast_outer_request.padata = pa_array; + if(retval == 0) + retval = encoder(&state->fast_outer_request, &local_encoded_result); + if (retval == 0) { + *encoded_request = local_encoded_result; + local_encoded_result = NULL; + } + if (encoded_armored_req) + krb5_free_data(context, encoded_armored_req); + if (armored_req) { + armored_req->armor = NULL; /*owned by state*/ + krb5_free_fast_armored_req(context, armored_req); + } + if (encoded_fast_req) + krb5_free_data(context, encoded_fast_req); + if (local_encoded_result) + krb5_free_data(context, local_encoded_result); + state->fast_outer_request.padata = NULL; + return retval; +} + +static krb5_error_code decrypt_fast_reply +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_pa_data **in_padata, + krb5_fast_response **response) +{ + krb5_error_code retval = 0; + krb5_data scratch; + krb5_enc_data *encrypted_response = NULL; + krb5_pa_data *fx_reply = NULL; + krb5_fast_response *local_resp = NULL; + assert(state != NULL); + assert(state->armor_key); + fx_reply = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_FX_FAST); + if (fx_reply == NULL) + retval = KRB5_ERR_FAST_REQUIRED; + if (retval == 0) { + scratch.data = (char *) fx_reply->contents; + scratch.length = fx_reply->length; + retval = decode_krb5_pa_fx_fast_reply(&scratch, &encrypted_response); + } + scratch.data = NULL; + if (retval == 0) { + scratch.data = malloc(encrypted_response->ciphertext.length); + if (scratch.data == NULL) + retval = ENOMEM; + scratch.length = encrypted_response->ciphertext.length; + } + if (retval == 0) + retval = krb5_c_decrypt(context, state->armor_key, + KRB5_KEYUSAGE_FAST_REP, NULL, + encrypted_response, &scratch); + if (retval != 0) { + const char * errmsg; + errmsg = krb5_get_error_message(context, retval); + krb5_set_error_message(context, retval, "%s while decrypting FAST reply", errmsg); + krb5_free_error_message(context, errmsg); + } + if (retval == 0) + retval = decode_krb5_fast_response(&scratch, &local_resp); + if (retval == 0) { + if (local_resp->nonce != state->nonce) { + retval = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, retval, "nonce modified in FAST response: KDC response modified"); + } + } + if (retval == 0) { + *response = local_resp; + local_resp = NULL; + } + if (scratch.data) + free(scratch.data); + if (encrypted_response) + krb5_free_enc_data(context, encrypted_response); + return retval; +} + +/* + * FAST separates two concepts: the set of padata we're using to + * decide what pre-auth mechanisms to use and the set of padata we're + * making available to mechanisms in order for them to respond to an + * error. The plugin interface in March 2009 does not permit + * separating these concepts for the plugins. This function makes + * both available for future revisions to the plugin interface. It + * also re-encodes the padata from the current error as a encoded + * typed-data and puts that in the e_data field. That will allow + * existing plugins with the old interface to find the error data. + * The output parameter out_padata contains the padata from the error + * whenever padata is available (all the time with fast). + */ +krb5_error_code +krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_state *state, + krb5_error **err_replyptr , krb5_pa_data ***out_padata, + krb5_boolean *retry) +{ + krb5_error_code retval = 0; + krb5_error *err_reply = *err_replyptr; + *out_padata = NULL; + *retry = 0; + if (state->armor_key) { + krb5_pa_data *fx_error_pa; + krb5_pa_data **result = NULL; + krb5_data scratch, *encoded_td = NULL; + krb5_error *fx_error = NULL; + krb5_fast_response *fast_response = NULL; + retval = decode_krb5_padata_sequence(&err_reply->e_data, &result); + if (retval == 0) + retval = decrypt_fast_reply(context, state, result, &fast_response); + if (retval) { + /*This can happen if the KDC does not understand FAST. We + * don't expect that, but treating it as the fatal error + * indicated by the KDC seems reasonable. + */ + *retry = 0; + krb5_free_pa_data(context, result); + return 0; + } + krb5_free_pa_data(context, result); + result = NULL; + if (retval == 0) { + fx_error_pa = krb5int_find_pa_data(context, fast_response->padata, KRB5_PADATA_FX_ERROR); + if (fx_error_pa == NULL) { + krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Expecting FX_ERROR pa-data inside FAST container"); + retval = KRB5KDC_ERR_PREAUTH_FAILED; + } + } + if (retval == 0) { + scratch.data = (char *) fx_error_pa->contents; + scratch.length = fx_error_pa->length; + retval = decode_krb5_error(&scratch, &fx_error); + } + /* + * krb5_pa_data and krb5_typed_data are safe to cast between: + * they have the same type fields in the same order. + * (krb5_preauthtype is a krb5_int32). If krb5_typed_data is + * ever changed then this will need to be a copy not a cast. + */ + if (retval == 0) + retval = encode_krb5_typed_data( (krb5_typed_data **) fast_response->padata, + &encoded_td); + if (retval == 0) { + fx_error->e_data = *encoded_td; + free(encoded_td); /*contents owned by fx_error*/ + encoded_td = NULL; + krb5_free_error(context, err_reply); + *err_replyptr = fx_error; + fx_error = NULL; + *out_padata = fast_response->padata; + fast_response->padata = NULL; + /* + * If there is more than the fx_error padata, then we want + * to retry the error + */ + *retry = (*out_padata)[1] != NULL; + } + if (fx_error) + krb5_free_error(context, fx_error); + krb5_free_fast_response(context, fast_response); + } else { /*not FAST*/ + *retry = (err_reply->e_data.length > 0); + if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED + ||err_reply->error == KDC_ERR_PREAUTH_FAILED) && err_reply->e_data.length) { + krb5_pa_data **result = NULL; + retval = decode_krb5_padata_sequence(&err_reply->e_data, &result); + if (retval == 0) + if (retval == 0) { + *out_padata = result; + + return 0; + } + krb5_free_pa_data(context, result); + krb5_set_error_message(context, retval, + "Error decoding padata in error reply"); + return retval; + } + } + return retval; +} + + +krb5_error_code krb5int_fast_process_response +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_rep *resp, + krb5_keyblock **as_key) +{ + krb5_error_code retval = 0; + krb5_fast_response *fast_response = NULL; + krb5_data *encoded_ticket = NULL; + krb5_boolean cksum_valid; + krb5_clear_error_message(context); + *as_key = NULL; + if (state->armor_key == 0) + return 0; + retval = decrypt_fast_reply(context, state, resp->padata, + &fast_response); + if (retval == 0) { + if (fast_response->finished == 0) { + retval = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, retval, "FAST response missing finish message in KDC reply"); + } + } + if (retval == 0) + retval = encode_krb5_ticket(resp->ticket, &encoded_ticket); + if (retval == 0) + retval = krb5_c_verify_checksum(context, state->armor_key, + KRB5_KEYUSAGE_FAST_FINISHED, + encoded_ticket, + &fast_response->finished->ticket_checksum, + &cksum_valid); + if (retval == 0 && cksum_valid == 0) { + retval = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, retval, "ticket modified in KDC reply"); + } + if (retval == 0) { + krb5_free_principal(context, resp->client); + resp->client = fast_response->finished->client; + fast_response->finished->client = NULL; + *as_key = fast_response->rep_key; + fast_response->rep_key = NULL; + krb5_free_pa_data(context, resp->padata); + resp->padata = fast_response->padata; + fast_response->padata = NULL; + } + if (fast_response) + krb5_free_fast_response(context, fast_response); + if (encoded_ticket) + krb5_free_data(context, encoded_ticket); + return retval; +} +krb5_error_code +krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state) +{ + krb5_error_code retval = 0; + struct krb5int_fast_request_state *local_state ; + local_state = malloc(sizeof *local_state); + if (local_state == NULL) + return ENOMEM; + memset(local_state, 0, sizeof(*local_state)); + *state = local_state; + return 0; +} + +void +krb5int_fast_free_state( krb5_context context, struct krb5int_fast_request_state *state) +{ + /*We are responsible for none of the store in the fast_outer_req*/ + krb5_free_keyblock(context, state->armor_key); + krb5_free_fast_armor(context, state->armor); + if (state->cookie) { + free(state->cookie->contents); + free(state->cookie); + state->cookie = NULL; + } + free(state); +} + +krb5_pa_data * krb5int_find_pa_data +(krb5_context context, krb5_pa_data *const *padata, krb5_preauthtype pa_type) +{ + krb5_pa_data * const *tmppa; + + if (padata == NULL) + return NULL; + + for (tmppa = padata; *tmppa != NULL; tmppa++) { + if ((*tmppa)->pa_type == pa_type) + break; + } + + return *tmppa; +} + diff --git a/src/lib/krb5/krb/fast.h b/src/lib/krb5/krb/fast.h new file mode 100644 index 000000000..e21df6504 --- /dev/null +++ b/src/lib/krb5/krb/fast.h @@ -0,0 +1,77 @@ +/* + * lib/krb5/krb/fast.h + * + * 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. + * + * + * <<< Description >>> + */ +#ifndef KRB_FAST_H + +#define KRB_FAST_H + +#include <k5-int.h> + +struct krb5int_fast_request_state { + krb5_kdc_req fast_outer_request; + krb5_keyblock *armor_key; /*non-null means fast is in use*/ + krb5_fast_armor *armor; + krb5_ui_4 fast_state_flags; + krb5_ui_4 fast_options; + krb5_pa_data *cookie; + krb5_int32 nonce; +}; + +krb5_error_code +krb5int_fast_prep_req_body(krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_req *request, krb5_data **encoded_req_body); + +typedef krb5_error_code(*kdc_req_encoder_proc) (const krb5_kdc_req *, krb5_data **); + +krb5_error_code +krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_req *request, + const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder, + krb5_data **encoded_request); +krb5_error_code +krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_state *state, + krb5_error **err_replyptr , krb5_pa_data ***out_padata, + krb5_boolean *retry); + +krb5_error_code krb5int_fast_process_response +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_kdc_rep *resp, + krb5_keyblock **as_key); + +krb5_error_code +krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state); + +void +krb5int_fast_free_state( krb5_context , struct krb5int_fast_request_state *state); +krb5_error_code krb5int_fast_as_armor +(krb5_context context, struct krb5int_fast_request_state *state, + krb5_gic_opt_ext *opte, + krb5_kdc_req *request); + + +#endif diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index f82e2a81e..30a38cdae 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -32,6 +32,7 @@ #include "k5-int.h" #include "int-proto.h" #include "os-proto.h" +#include "fast.h" #if APPLE_PKINIT #define IN_TKT_DEBUG 0 @@ -967,6 +968,7 @@ krb5_get_init_creds(krb5_context context, krb5_data salt; krb5_data s2kparams; krb5_keyblock as_key; + krb5_keyblock *fast_as_key = NULL; krb5_error *err_reply; krb5_kdc_rep *local_as_reply; krb5_timestamp time_now; @@ -974,6 +976,10 @@ krb5_get_init_creds(krb5_context context, krb5_preauth_client_rock get_data_rock; int canon_flag = 0; krb5_principal_data referred_client; + krb5_boolean retry = 0; + struct krb5int_fast_request_state *fast_state = NULL; + krb5_pa_data **out_padata = NULL; + /* initialize everything which will be freed at cleanup */ @@ -988,7 +994,7 @@ krb5_get_init_creds(krb5_context context, preauth_to_use = NULL; kdc_padata = NULL; as_key.length = 0; - salt.length = 0; + salt.length = 0; salt.data = NULL; local_as_reply = 0; @@ -1002,6 +1008,9 @@ krb5_get_init_creds(krb5_context context, referred_client = *client; referred_client.realm.data = NULL; referred_client.realm.length = 0; + ret = krb5int_fast_make_state(context, &fast_state); + if (ret) + goto cleanup; /* * Set up the basic request structure @@ -1231,15 +1240,20 @@ krb5_get_init_creds(krb5_context context, /* XXX Yuck. Old version. */ request.nonce = (krb5_int32) time_now; } + ret = krb5int_fast_as_armor(context, fast_state, options, &request); + if (ret != 0) + goto cleanup; /* give the preauth plugins a chance to prep the request body */ krb5_preauth_prepare_request(context, options, &request); - ret = encode_krb5_kdc_req_body(&request, &encoded_request_body); + ret = krb5int_fast_prep_req_body(context, fast_state, + &request, &encoded_request_body); if (ret) 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) { @@ -1258,6 +1272,10 @@ krb5_get_init_creds(krb5_context context, gak_fct, gak_data, &get_data_rock, options))) goto cleanup; + if (out_padata) { + krb5_free_pa_data(context, out_padata); + out_padata = NULL; + } } else { if (preauth_to_use != NULL) { /* @@ -1293,7 +1311,9 @@ krb5_get_init_creds(krb5_context context, krb5_free_data(context, encoded_previous_request); encoded_previous_request = NULL; } - ret = encode_krb5_as_req(&request, &encoded_previous_request); + ret = krb5int_fast_prep_req(context, fast_state, + &request, encoded_request_body, + encode_krb5_as_req, &encoded_previous_request); if (ret) goto cleanup; @@ -1305,15 +1325,19 @@ krb5_get_init_creds(krb5_context context, goto cleanup; if (err_reply) { - if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED && - err_reply->e_data.length > 0) { + ret = krb5int_fast_process_error(context, fast_state, &err_reply, + &out_padata, &retry); + if (ret !=0) + goto cleanup; + if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED ||err_reply->error == KDC_ERR_PREAUTH_FAILED) +&& retry) { /* reset the list of preauth types to try */ if (preauth_to_use) { krb5_free_pa_data(context, preauth_to_use); preauth_to_use = NULL; } - ret = decode_krb5_padata_sequence(&err_reply->e_data, - &preauth_to_use); + preauth_to_use = out_padata; + out_padata = NULL; krb5_free_error(context, err_reply); err_reply = NULL; if (ret) @@ -1345,7 +1369,7 @@ krb5_get_init_creds(krb5_context context, goto cleanup; request.client = &referred_client; } else { - if (err_reply->e_data.length > 0) { + if (retry) { /* continue to next iteration */ } else { /* error + no hints = give up */ @@ -1374,10 +1398,14 @@ krb5_get_init_creds(krb5_context context, /* process any preauth data in the as_reply */ krb5_clear_preauth_context_use_counts(context); + ret = krb5int_fast_process_response(context, fast_state, + local_as_reply, &fast_as_key); + if (ret) + goto cleanup; 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, @@ -1419,8 +1447,14 @@ krb5_get_init_creds(krb5_context context, it. If decrypting the as_rep fails, or if there isn't an as_key at all yet, then use the gak_fct to get one, and try again. */ - - if (as_key.length) + if (fast_as_key) { + if (as_key.length) + krb5_free_keyblock_contents(context, &as_key); + as_key = *fast_as_key; + free(fast_as_key); + fast_as_key = NULL; + } + if (as_key.length) ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, NULL, &as_key, krb5_kdc_rep_decrypt_proc, NULL); @@ -1477,6 +1511,11 @@ cleanup: } } krb5_preauth_request_context_fini(context); + krb5_free_keyblock(context, fast_as_key); + if (fast_state) + krb5int_fast_free_state(context, fast_state); + if (out_padata) + krb5_free_pa_data(context, out_padata); if (encoded_previous_request != NULL) { krb5_free_data(context, encoded_previous_request); encoded_previous_request = NULL; diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index 348637ca3..72203f0e7 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -146,6 +146,8 @@ krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte) /* Free up any private stuff */ if (opte->opt_private->preauth_data != NULL) free_gic_opt_ext_preauth_data(context, opte); + if (opte->opt_private->fast_ccache_name) + free(opte->opt_private->fast_ccache_name); free(opte->opt_private); opte->opt_private = NULL; return 0; @@ -465,3 +467,21 @@ krb5_get_init_creds_opt_free_pa(krb5_context context, } free(preauth_data); } +krb5_error_code KRB5_CALLCONV krb5_get_init_creds_opt_set_fast_ccache_name +(krb5_context context, krb5_get_init_creds_opt *opt, const char *ccache_name) +{ + krb5_error_code retval = 0; + krb5_gic_opt_ext *opte; + + retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0, + "krb5_get_init_creds_opt_set_fast_ccache_name"); + if (retval) + return retval; + if (opte->opt_private->fast_ccache_name) { + free(opte->opt_private->fast_ccache_name); + } + opte->opt_private->fast_ccache_name = strdup(ccache_name); + if (opte->opt_private->fast_ccache_name == NULL) + retval = ENOMEM; + return retval; +} diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c index e0e71746d..d17d46bc7 100644 --- a/src/lib/krb5/krb/kfree.c +++ b/src/lib/krb5/krb/kfree.c @@ -54,6 +54,7 @@ */ #include "k5-int.h" +#include <assert.h> void KRB5_CALLCONV krb5_free_address(krb5_context context, krb5_address *val) @@ -344,6 +345,7 @@ krb5_free_kdc_req(krb5_context context, krb5_kdc_req *val) { if (val == NULL) return; + assert( val->kdc_state == NULL); krb5_free_pa_data(context, val->padata); krb5_free_principal(context, val->client); krb5_free_principal(context, val->server); @@ -795,3 +797,63 @@ krb5_free_etype_list(krb5_context context, free(etypes); } } +void krb5_free_fast_req(krb5_context context, krb5_fast_req *val) +{ + if (val == NULL) + return; + krb5_free_kdc_req(context, val->req_body); + free(val); +} + +void krb5_free_fast_armor(krb5_context context, krb5_fast_armor *val) +{ + if (val == NULL) + return; + krb5_free_data_contents(context, &val->armor_value); + free(val); +} + +void krb5_free_fast_response(krb5_context context, krb5_fast_response *val) +{ + if (!val) + return; + krb5_free_pa_data(context, val->padata); + krb5_free_fast_finished(context, val->finished); + free(val); +} + +void krb5_free_fast_finished +(krb5_context context, krb5_fast_finished *val) +{ + if (!val) + return; + krb5_free_principal(context, val->client); + krb5_free_checksum_contents(context, &val->ticket_checksum); + free(val); +} + +void krb5_free_typed_data(krb5_context context, krb5_typed_data **in) +{ + int i = 0; + if (in == NULL) return; + while (in[i] != NULL) { + if (in[i]->data != NULL) + free(in[i]->data); + free(in[i]); + i++; + } + free(in); +} + +void krb5_free_fast_armored_req(krb5_context context, + krb5_fast_armored_req *val) +{ + if (val == NULL) + return; + if (val->armor) + krb5_free_fast_armor(context, val->armor); + krb5_free_data_contents(context, &val->enc_part.ciphertext); + if (val->req_checksum.contents) + krb5_free_checksum_contents(context, &val->req_checksum); + free(val); +} diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ccb4af234..4c7dd5e60 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/libkrb5.exports b/src/lib/krb5/libkrb5.exports index c41d2e811..f30b57114 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -19,6 +19,8 @@ decode_krb5_encryption_key decode_krb5_error decode_krb5_etype_info decode_krb5_etype_info2 +decode_krb5_fast_req +decode_krb5_pa_fx_fast_request decode_krb5_kdc_req_body decode_krb5_pa_enc_ts decode_krb5_pa_for_user @@ -36,6 +38,7 @@ decode_krb5_setpw_req decode_krb5_tgs_rep decode_krb5_tgs_req decode_krb5_ticket +decode_krb5_typed_data encode_krb5_alt_method encode_krb5_ap_rep encode_krb5_ap_rep_enc_part @@ -56,6 +59,8 @@ encode_krb5_encryption_key encode_krb5_error encode_krb5_etype_info encode_krb5_etype_info2 +encode_krb5_fast_response +encode_krb5_pa_fx_fast_reply encode_krb5_kdc_req_body encode_krb5_pa_enc_ts encode_krb5_pa_for_user @@ -226,6 +231,8 @@ krb5_free_enc_tkt_part krb5_free_error krb5_free_error_message krb5_free_etype_info +krb5_free_fast_armored_req +krb5_free_fast_req krb5_free_host_realm krb5_free_kdc_rep krb5_free_kdc_req @@ -266,6 +273,7 @@ krb5_free_tgt_creds krb5_free_ticket krb5_free_tickets krb5_free_tkt_authent +krb5_free_typed_data krb5_free_unparsed_name krb5_fwd_tgt_creds krb5_gen_portaddr @@ -300,6 +308,7 @@ krb5_get_init_creds_opt_set_address_list krb5_get_init_creds_opt_set_canonicalize krb5_get_init_creds_opt_set_change_password_prompt krb5_get_init_creds_opt_set_etype_list +krb5_get_init_creds_opt_set_fast_ccache_name krb5_get_init_creds_opt_set_forwardable krb5_get_init_creds_opt_set_pa krb5_get_init_creds_opt_set_preauth_list @@ -516,6 +525,8 @@ krb5int_cc_default krb5int_cleanup_library krb5int_cm_call_select krb5int_copy_data_contents_add0 +krb5int_find_authdata +krb5int_find_pa_data krb5int_foreach_localaddr krb5int_free_addrlist krb5int_init_context_kdc diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index 1bf171a6f..bb66568db 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 }; |
