#define UNSUPPORTED_CRITICAL_FAST_OPTIONS 0x00ff
#define KRB5_FAST_OPTION_HIDE_CLIENT_NAMES 0x01
- typedef struct _krb5_fast_finished {
- krb5_timestamp timestamp;
- krb5_int32 usec;
- krb5_principal client;
- krb5_checksum checksum;
- krb5_checksum ticket_checksum;
- } krb5_fast_finished;
-
- typedef struct _krb5_fast_response {
- krb5_magic magic;
+typedef struct _krb5_fast_finished {
+ krb5_timestamp timestamp;
+ krb5_int32 usec;
+ krb5_principal client;
+ krb5_checksum ticket_checksum;
+} krb5_fast_finished;
+
+typedef struct _krb5_fast_response {
+ krb5_magic magic;
krb5_pa_data **padata;
krb5_keyblock *rep_key;
krb5_fast_finished *finished;
+ krb5_int32 nonce;
} krb5_fast_response;
}
}
retval = kdc_fast_handle_error(kdc_context, rstate,
- pa, &errpkt);
+ request, pa, &errpkt);
if (retval == 0)
retval = krb5_mk_error(kdc_context, &errpkt, scratch);
free(errpkt.text.data);
krb5_clear_error_message(kdc_context);
fast_padata = find_pa_data(request->padata,
KRB5_PADATA_FX_FAST);
- cookie_padata = find_pa_data(request->padata, KRB5_PADATA_FX_COOKIE);
- if (fast_padata == NULL)
- return 0; /*no fast*/
-
+ if (fast_padata != NULL){
scratch.length = fast_padata->length;
scratch.data = (char *) fast_padata->contents;
retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) !=0)
retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
}
- if (retval == 0 && cookie_padata != NULL) {
+ if (retval == 0)
+ cookie_padata = find_pa_data(fast_req->req_body->padata, KRB5_PADATA_FX_COOKIE);
+ if (retval == 0) {
+ state->fast_options = fast_req->fast_options;
+ if (request->kdc_state == state)
+ request->kdc_state = NULL;
+ krb5_free_kdc_req( kdc_context, request);
+ *requestptr = fast_req->req_body;
+ fast_req->req_body = NULL;
+
+ }
+ }
+ else cookie_padata = find_pa_data(request->padata, KRB5_PADATA_FX_COOKIE);
+ if (retval == 0 && cookie_padata != NULL) {
krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data));
if (new_padata != NULL) {
retval = ENOMEM;
}
}
}
- if (retval == 0) {
- state->fast_options = fast_req->fast_options;
- if (request->kdc_state == state)
- request->kdc_state = NULL;
- krb5_free_kdc_req( kdc_context, request);
- *requestptr = fast_req->req_body;
- fast_req->req_body = NULL;
-
- }
- if (fast_req)
+ if (fast_req)
krb5_free_fast_req( kdc_context, fast_req);
if (fast_armored_req)
krb5_free_fast_armored_req(kdc_context, fast_armored_req);
}
krb5_error_code kdc_fast_response_handle_padata
-(struct kdc_request_state *state, krb5_kdc_rep *rep, const krb5_data *pkt)
+(struct kdc_request_state *state,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *rep)
{
krb5_error_code retval = 0;
krb5_fast_finished finish;
return 0;
memset(&finish, 0, sizeof(finish));
fast_response.padata = rep->padata;
- fast_response.rep_key = state->reply_key;
+ fast_response.rep_key = state->reply_key;
+ fast_response.nonce = request->nonce;
fast_response.finished = &finish;
finish.client = rep->client;
pa_array = calloc(3, sizeof(*pa_array));
retval = krb5_c_make_checksum(kdc_context, cksumtype,
state->armor_key, KRB5_KEYUSAGE_FAST_FINISHED,
encoded_ticket, &finish.ticket_checksum);
-/* xxx checksum should be something else; sticking ticket_checksum there is a placeholder*/
- if (retval == 0)
- retval = krb5_c_make_checksum(kdc_context, cksumtype,
- state->armor_key, KRB5_KEYUSAGE_FAST_FINISHED,
- encoded_ticket, &finish.checksum);
if (retval == 0)
retval = encode_krb5_fast_response(&fast_response, &encoded_fast_response);
if (retval == 0) {
krb5_free_data(kdc_context, encoded_fast_response);
if (encoded_ticket)
krb5_free_data(kdc_context, encoded_ticket);
- if (finish.checksum.contents)
- krb5_free_checksum_contents(kdc_context, &finish.checksum);
if (finish.ticket_checksum.contents)
- krb5_free_checksum_contents(kdc_context, &finish.checksum);
+ krb5_free_checksum_contents(kdc_context, &finish.ticket_checksum);
return retval;
}
*/
krb5_error_code kdc_fast_handle_error
(krb5_context context, struct kdc_request_state *state,
+ krb5_kdc_req *request,
krb5_pa_data **in_padata, krb5_error *err)
{
krb5_error_code retval = 0;
pa[0].contents = (unsigned char *) encoded_fx_error->data;
inner_pa[size++] = &pa[0];
resp.padata = inner_pa;
+ resp.nonce = request->nonce;
resp.rep_key = NULL;
resp.finished = NULL;
}
struct kdc_request_state *state);
krb5_error_code kdc_fast_response_handle_padata
-(struct kdc_request_state *state, krb5_kdc_rep *rep, const krb5_data *pkt);
+(struct kdc_request_state *state,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *rep);
krb5_error_code kdc_fast_handle_error
(krb5_context context, struct kdc_request_state *state,
+ krb5_kdc_req *request,
krb5_pa_data **in_padata, krb5_error *err);
{
setup();
val->client = NULL;
- val->checksum.contents = NULL;
val->ticket_checksum.contents = NULL;
{begin_structure();
get_field(val->timestamp, 0, asn1_decode_kerberos_time);
alloc_field(val->client);
get_field(val->client, 2, asn1_decode_realm);
get_field(val->client, 3, asn1_decode_principal_name);
- get_field(val->checksum, 4, asn1_decode_checksum);
- get_field(val->ticket_checksum, 5, asn1_decode_checksum);
+ 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->checksum);
krb5_free_checksum_contents( NULL, &val->ticket_checksum);
return retval;
}
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, checksum, 4),
- FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 5),
+ FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 4),
};
DEFSEQTYPE( fast_finished, krb5_fast_finished, fast_finished_fields, 0);
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)
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);
- end_structure(); }
+ get_field(rep->nonce, 3, asn1_decode_int32);
+ end_structure(); }
rep->magic = KV5M_FAST_RESPONSE;
cleanup(free);
}
krb5_error_code
krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state,
- const krb5_kdc_req *request,
+ krb5_kdc_req *request,
const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder,
krb5_data **encoded_request)
{
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);
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 *));
krb5_free_pa_data(context, result);
result = NULL;
if (retval == 0) {
+ if (fast_response->nonce != state->nonce) {
+ krb5_set_error_message(context, KRB5_KDCREP_MODIFIED, "Nonce in reply did not match expected value");
+ retval = KRB5_KDCREP_MODIFIED;
+ }
+ }
+ 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");
krb5_ui_4 fast_state_flags;
krb5_ui_4 fast_options;
krb5_data cookie_contents;
+ krb5_int32 nonce;
};
krb5_error_code
krb5_error_code
krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state,
- const krb5_kdc_req *request,
+ krb5_kdc_req *request,
const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder,
krb5_data **encoded_request);
krb5_error_code
if (!val)
return;
krb5_free_principal(context, val->client);
- krb5_free_checksum_contents(context, &val->checksum);
krb5_free_checksum_contents(context, &val->ticket_checksum);
free(val);
}