#include "k5-int.h"
#include "int-proto.h"
+#include "fast.h"
/*
Takes a KDC_REP message and decrypts encrypted part using etype and
*/
krb5_error_code
-krb5int_decode_tgs_rep(krb5_context context, krb5_data *enc_rep, const krb5_keyblock *key,
+krb5int_decode_tgs_rep(krb5_context context,
+ struct krb5int_fast_request_state *fast_state,
+krb5_data *enc_rep, const krb5_keyblock *key,
krb5_keyusage usage, krb5_kdc_rep **dec_rep)
{
krb5_error_code retval;
krb5_kdc_rep *local_dec_rep;
+ krb5_keyblock *strengthen_key = NULL, tgs_key;
+ tgs_key.contents = NULL;
if (krb5_is_as_rep(enc_rep)) {
retval = decode_krb5_as_rep(enc_rep, &local_dec_rep);
if (retval)
return retval;
- if ((retval = krb5_kdc_rep_decrypt_proc(context, key, &usage,
+ retval = krb5int_fast_process_response(context, fast_state,
+ local_dec_rep, &strengthen_key);
+ if (retval == KRB5_ERR_FAST_REQUIRED)
+ retval = 0;
+ else if (retval)
+ goto cleanup;
+ retval = krb5int_fast_reply_key(context, strengthen_key, key, &tgs_key);
+ if (retval)
+ goto cleanup;
+
+ if ((retval = krb5_kdc_rep_decrypt_proc(context, &tgs_key, &usage,
local_dec_rep)))
krb5_free_kdc_rep(context, local_dec_rep);
else
*dec_rep = local_dec_rep;
- return(retval);
-}
+cleanup:
+ krb5_free_keyblock(context, strengthen_key);
+ krb5_free_keyblock_contents(context, &tgs_key);
+ return (retval);
+ }
return retval;
}
+krb5_error_code krb5int_fast_tgs_armor(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_keyblock *subkey,krb5_keyblock *session_key,
+ krb5_ccache ccache,
+ krb5_data *target_realm)
+{
+ krb5_principal target_principal = NULL;
+ krb5_keyblock *existing_armor = NULL;
+ krb5_error_code retval = 0;
+
+ if (ccache) {
+ retval = krb5int_tgtname(context, target_realm, target_realm,
+ &target_principal);
+ if (retval == 0)
+ retval = fast_armor_ap_request(context, state, ccache, target_principal);
+ if (retval == 0) {
+ existing_armor = state->armor_key;
+ state->armor_key = NULL;
+ retval = krb5_c_fx_cf2_simple(context, existing_armor,
+ "explicitarmor", subkey,
+ "tgsarmor", &state->armor_key);
+ }
+ } else retval = krb5_c_fx_cf2_simple(context,
+ subkey, "subkeyarmor",
+ session_key, "ticketarmor", &state->armor_key);
+ if (target_principal)
+ krb5_free_principal(context, target_principal);
+ krb5_free_keyblock(context, existing_armor);
+ return retval;
+}
+
+
krb5_error_code
krb5int_fast_prep_req_body(krb5_context context,
struct krb5int_fast_request_state *state,
krb5_data **encoded_request)
{
krb5_error_code retval = 0;
- krb5_pa_data *pa_array[2];
+ krb5_pa_data *pa_array[3];
krb5_pa_data pa[2];
krb5_fast_req fast_req;
- krb5_fast_armored_req *armored_req = NULL;
+ krb5_pa_data *tgs = NULL;
+ 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;
+ int i,j;
assert(state != NULL);
assert(state->fast_outer_request.padata == NULL);
retval = ENOMEM;
}
fast_req.fast_options = state->fast_options;
+ if (retval == 0
+ && (tgs = krb5int_find_pa_data(context,fast_req.req_body->padata,
+ KRB5_PADATA_AP_REQ))) {
+ krb5_pa_data **paptr = &fast_req.req_body->padata[0];
+ for (i=0,j=0;paptr[j]; j++)
+ if (paptr[j]->pa_type == KRB5_PADATA_AP_REQ)
+ paptr[j] = NULL;
+ else paptr[i++] = paptr[j];
+ paptr[i++] = NULL;
+ }
if (retval == 0)
retval = encode_krb5_fast_req(&fast_req, &encoded_fast_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];
+ if (tgs) {
+ pa_array[0] = tgs;
+ pa_array[1] = &pa[0];
+ } else pa_array[0] = &pa[0];
}
state->fast_outer_request.padata = pa_array;
if(retval == 0)
krb5int_upgrade_to_fast_p(krb5_context context,
struct krb5int_fast_request_state *state,
krb5_pa_data **padata);
+krb5_error_code krb5int_fast_tgs_armor(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_keyblock *subkey,
+ krb5_keyblock *session_key,
+ krb5_ccache ccache,
+ krb5_data *target_realm);
#endif
#include "k5-int.h"
#include "int-proto.h"
+#include "fast.h"
+
static krb5_error_code
kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address,
krb5_error_code
krb5int_make_tgs_request(krb5_context context,
+ struct krb5int_fast_request_state *fast_state,
krb5_creds *tkt,
krb5_flags kdcoptions,
krb5_address *const *address,
enctypes[1] = 0;
}
- retval = krb5int_make_tgs_request_ext(context, kdcoptions, &in_cred->times,
+ retval = krb5int_make_tgs_request_ext(context, fast_state, kdcoptions, &in_cred->times,
enctypes, in_cred->server, address,
in_cred->authdata, in_padata,
second_tkt ?
krb5_error_code
krb5int_process_tgs_reply(krb5_context context,
+ struct krb5int_fast_request_state *fast_state,
krb5_data *response_data,
krb5_creds *tkt,
krb5_flags kdcoptions,
retval = decode_krb5_error(response_data, &err_reply);
if (retval != 0)
goto cleanup;
+ retval = krb5int_fast_process_error(context, fast_state,
+ &err_reply, NULL, NULL);
+ if (retval)
+ goto cleanup;
retval = (krb5_error_code) err_reply->error + ERROR_TABLE_BASE_krb5;
if (err_reply->text.length > 0) {
switch (err_reply->error) {
/* Unfortunately, Heimdal at least up through 1.2 encrypts using
the session key not the subsession key. So we try both. */
- retval = krb5int_decode_tgs_rep(context, response_data,
+ retval = krb5int_decode_tgs_rep(context, fast_state,
+ response_data,
subkey,
KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY,
&dec_rep);
if (retval) {
TRACE_TGS_REPLY_DECODE_SESSION(context, &tkt->keyblock);
- if ((krb5int_decode_tgs_rep(context, response_data,
+ if ((krb5int_decode_tgs_rep(context, fast_state, response_data,
&tkt->keyblock,
KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY, &dec_rep)) == 0)
retval = 0;
krb5_int32 nonce;
krb5_keyblock *subkey = NULL;
int tcp_only = 0, use_master = 0;
+ struct krb5int_fast_request_state *fast_state = NULL;
request_data.data = NULL;
request_data.length = 0;
response_data.data = NULL;
response_data.length = 0;
+ retval = krb5int_fast_make_state(context, &fast_state);
+ if (retval)
+ goto cleanup;
+
#ifdef DEBUG_REFERRALS
printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off");
krb5int_dbgref_dump_principal("krb5_get_cred_via_tkt requested ticket", in_cred->server);
krb5int_dbgref_dump_principal("krb5_get_cred_via_tkt TGT in use", tkt->server);
#endif
- retval = krb5int_make_tgs_request(context, tkt, kdcoptions,
+ retval = krb5int_make_tgs_request(context, fast_state, tkt, kdcoptions,
address, in_padata, in_cred,
pacb_fct, pacb_data,
&request_data, ×tamp, &nonce,
retval = decode_krb5_error(&response_data, &err_reply);
if (retval != 0)
goto cleanup;
+ retval = krb5int_fast_process_error(context, fast_state,
+ &err_reply, NULL, NULL);
+ if (retval)
+ goto cleanup;
if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
tcp_only = 1;
krb5_free_error(context, err_reply);
} else
goto cleanup;
- retval = krb5int_process_tgs_reply(context, &response_data,
+ retval = krb5int_process_tgs_reply(context, fast_state, &response_data,
tkt, kdcoptions, address,
in_padata, in_cred,
timestamp, nonce, subkey,
goto cleanup;
cleanup:
+ krb5int_fast_free_state(context, fast_state);
#ifdef DEBUG_REFERRALS
printf("krb5_get_cred_via_tkt ending; %s\n", retval?error_message(retval):"no error");
#endif
#include "k5-int.h"
#include "int-proto.h"
+#include "fast.h"
/*
* Set *mcreds and *fields to a matching credential and field set for
krb5_flags req_options; /* Caller-requested KRB5_GC_* options */
krb5_flags req_kdcopt; /* Caller-requested options as KDC options */
krb5_authdata **authdata; /* Caller-requested authdata */
+ struct krb5int_fast_request_state *fast_state;
/* The following fields are used in multiple steps. */
krb5_creds *cur_tgt; /* TGT to be used for next query */
if (!krb5_c_valid_enctype(ctx->cur_tgt->keyblock.enctype))
return KRB5_PROG_ETYPE_NOSUPP;
- code = krb5int_make_tgs_request(context, ctx->cur_tgt, ctx->kdcopt,
+ code = krb5int_make_tgs_request(context, ctx->fast_state,
+ ctx->cur_tgt, ctx->kdcopt,
ctx->cur_tgt->addresses, NULL,
ctx->tgs_in_creds, NULL, NULL, &request,
&ctx->timestamp, &ctx->nonce,
krb5_free_creds(context, ctx->reply_creds);
ctx->reply_creds = NULL;
- code = krb5int_process_tgs_reply(context, reply, ctx->cur_tgt, ctx->kdcopt,
+ code = krb5int_process_tgs_reply(context, ctx->fast_state,
+ reply, ctx->cur_tgt, ctx->kdcopt,
ctx->cur_tgt->addresses, NULL,
ctx->tgs_in_creds, ctx->timestamp,
ctx->nonce, ctx->subkey, NULL, NULL,
ctx = k5alloc(sizeof(*ctx), &code);
if (ctx == NULL)
goto cleanup;
+ code = krb5int_fast_make_state(context, &ctx->fast_state);
+ if (code)
+ goto cleanup;
ctx->req_options = options;
ctx->req_kdcopt = 0;
{
if (ctx == NULL)
return;
+ krb5int_fast_free_state(context, ctx->fast_state);
krb5_free_creds(context, ctx->in_creds);
krb5_cc_close(context, ctx->ccache);
krb5_free_principal(context, ctx->req_server);
#ifndef KRB5_INT_FUNC_PROTO__
#define KRB5_INT_FUNC_PROTO__
+struct krb5int_fast_request_state;
+
krb5_error_code
krb5int_tgtname(krb5_context context, const krb5_data *, const krb5_data *,
krb5_principal *);
krb5_error_code
krb5int_make_tgs_request_ext(krb5_context context,
+ struct krb5int_fast_request_state *,
krb5_flags kdcoptions,
const krb5_ticket_times *timestruct,
const krb5_enctype *ktypes,
krb5_error_code
krb5int_make_tgs_request(krb5_context context,
+ struct krb5int_fast_request_state *,
krb5_creds *tkt,
krb5_flags kdcoptions,
krb5_address *const *address,
krb5_error_code
krb5int_process_tgs_reply(krb5_context context,
+ struct krb5int_fast_request_state *,
krb5_data *response_data,
krb5_creds *tkt,
krb5_flags kdcoptions,
* in with the subkey needed to decrypt the TGS
* response. Otherwise it will be set to null.
*/
-krb5_error_code krb5int_decode_tgs_rep(krb5_context, krb5_data *,
+krb5_error_code krb5int_decode_tgs_rep(krb5_context,
+ struct krb5int_fast_request_state *,
+ krb5_data *,
const krb5_keyblock *, krb5_keyusage,
krb5_kdc_rep ** );
#include "k5-int.h"
#include "int-proto.h"
+#include "fast.h"
/*
Constructs a TGS request
krb5_error_code
krb5int_make_tgs_request_ext(krb5_context context,
+ struct krb5int_fast_request_state *fast_state,
krb5_flags kdcoptions,
const krb5_ticket_times *timestruct,
const krb5_enctype *ktypes,
return retval;
TRACE_SEND_TGS_SUBKEY(context, local_subkey);
- if (authorization_data) {
+ retval = krb5int_fast_tgs_armor(context, fast_state, local_subkey,
+ &in_cred->keyblock, NULL, NULL);
+ if (retval)
+ goto cleanup;
+ if (authorization_data) {
/* need to encrypt it in the request */
if ((retval = encode_krb5_authdata(authorization_data, &scratch)))
tgsreq.second_ticket = 0;
/* encode the body; then checksum it */
- if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
+ if ((retval = krb5int_fast_prep_req_body(context, fast_state, &tgsreq, &scratch)))
goto cleanup;
/*
goto cleanup;
}
/* the TGS_REQ is assembled in tgsreq, so encode it */
- if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch)))
+ if ((retval = krb5int_fast_prep_req(context, fast_state, &tgsreq,
+ &scratch2, encode_krb5_tgs_req,
+ &scratch)))
goto cleanup;
*request_data = *scratch;