Skip to content

Commit

Permalink
FAST TGS
Browse files Browse the repository at this point in the history
Implement RFC 6113 FAST TGS support.

Includes library support for a varient of explicit TGS armor  that has not yet been proposed within the IETF.

ticket: 7026

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25488 dc483132-0cff-0310-8789-dd5450dbe970
  • Loading branch information
hartmans committed Nov 23, 2011
1 parent 64a0735 commit 09484d0
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 18 deletions.
26 changes: 22 additions & 4 deletions src/lib/krb5/krb/decode_kdc.c
Expand Up @@ -26,6 +26,7 @@

#include "k5-int.h"
#include "int-proto.h"
#include "fast.h"

/*
Takes a KDC_REP message and decrypts encrypted part using etype and
Expand All @@ -41,11 +42,15 @@
*/

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);
Expand All @@ -58,10 +63,23 @@ krb5int_decode_tgs_rep(krb5_context context, krb5_data *enc_rep, const krb5_keyb
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);
}
52 changes: 49 additions & 3 deletions src/lib/krb5/krb/fast.c
Expand Up @@ -106,6 +106,37 @@ fast_armor_ap_request(krb5_context context,
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,
Expand Down Expand Up @@ -200,13 +231,15 @@ krb5int_fast_prep_req(krb5_context context,
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);
Expand All @@ -224,6 +257,16 @@ krb5int_fast_prep_req(krb5_context context,
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) {
Expand All @@ -249,7 +292,10 @@ krb5int_fast_prep_req(krb5_context context,
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)
Expand Down
5 changes: 5 additions & 0 deletions src/lib/krb5/krb/fast.h
Expand Up @@ -102,5 +102,10 @@ krb5_boolean
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
29 changes: 24 additions & 5 deletions src/lib/krb5/krb/gc_via_tkt.c
Expand Up @@ -31,6 +31,8 @@

#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,
Expand Down Expand Up @@ -171,6 +173,7 @@ krb5_get_cred_via_tkt(krb5_context context, krb5_creds *tkt,

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,
Expand Down Expand Up @@ -214,7 +217,7 @@ krb5int_make_tgs_request(krb5_context context,
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 ?
Expand All @@ -230,6 +233,7 @@ krb5int_make_tgs_request(krb5_context context,

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,
Expand Down Expand Up @@ -257,6 +261,10 @@ krb5int_process_tgs_reply(krb5_context context,
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) {
Expand Down Expand Up @@ -292,13 +300,14 @@ krb5int_process_tgs_reply(krb5_context context,

/* 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;
Expand Down Expand Up @@ -416,19 +425,24 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt,
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, &timestamp, &nonce,
Expand All @@ -448,6 +462,10 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt,
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);
Expand All @@ -460,7 +478,7 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt,
} 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,
Expand All @@ -470,6 +488,7 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt,
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
Expand Down
12 changes: 10 additions & 2 deletions src/lib/krb5/krb/get_creds.c
Expand Up @@ -39,6 +39,7 @@

#include "k5-int.h"
#include "int-proto.h"
#include "fast.h"

/*
* Set *mcreds and *fields to a matching credential and field set for
Expand Down Expand Up @@ -151,6 +152,7 @@ struct _krb5_tkt_creds_context {
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 */
Expand Down Expand Up @@ -266,7 +268,8 @@ make_request(krb5_context context, krb5_tkt_creds_context ctx,
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,
Expand Down Expand Up @@ -354,7 +357,8 @@ get_creds_from_tgs_reply(krb5_context context, krb5_tkt_creds_context ctx,

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,
Expand Down Expand Up @@ -1043,6 +1047,9 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
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;
Expand Down Expand Up @@ -1110,6 +1117,7 @@ krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx)
{
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);
Expand Down
9 changes: 8 additions & 1 deletion src/lib/krb5/krb/int-proto.h
Expand Up @@ -27,6 +27,8 @@
#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 *);
Expand Down Expand Up @@ -89,6 +91,7 @@ krb5_get_cred_via_tkt_ext (krb5_context context, krb5_creds *tkt,

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,
Expand All @@ -110,6 +113,7 @@ krb5int_make_tgs_request_ext(krb5_context context,

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,
Expand All @@ -127,6 +131,7 @@ krb5int_make_tgs_request(krb5_context context,

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,
Expand All @@ -145,7 +150,9 @@ krb5int_process_tgs_reply(krb5_context context,
* 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 ** );

Expand Down

0 comments on commit 09484d0

Please sign in to comment.