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_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); } TRACE_FAST_ENCODE(context); /* 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 = krb5_c_make_checksum(context, 0, 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; }
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], **pa_tgs_array = NULL; krb5_pa_data pa[2]; krb5_fast_req fast_req; 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); memset(pa_array, 0, sizeof(pa_array)); if (state->armor_key == NULL) { return encoder(request, encoded_request); } TRACE_FAST_ENCODE(context); 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 && (tgs = krb5int_find_pa_data(context, fast_req.req_body->padata, KRB5_PADATA_AP_REQ)) != NULL) { krb5_pa_data **paptr = &fast_req.req_body->padata[0]; for (i = 0, j = 0; paptr[j] != NULL; 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) { 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 = krb5_c_make_checksum(context, 0, 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; if (tgs) { retval = make_tgs_outer_padata(tgs, pa, request->padata, &pa_tgs_array); state->fast_outer_request.padata = pa_tgs_array; } else { 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); if (tgs) { free(tgs->contents); free(tgs); } state->fast_outer_request.padata = NULL; free(pa_tgs_array); return retval; }
krb5_error_code kdc_find_fast(krb5_kdc_req **requestptr, krb5_data *checksummed_data, krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, struct kdc_request_state *state, krb5_data **inner_body_out) { krb5_error_code retval = 0; krb5_pa_data *fast_padata, *cookie_padata = NULL; krb5_data scratch, *inner_body = NULL; krb5_fast_req * fast_req = NULL; krb5_kdc_req *request = *requestptr; krb5_fast_armored_req *fast_armored_req = NULL; krb5_checksum *cksum; krb5_boolean cksum_valid; krb5_keyblock empty_keyblock; kdc_realm_t *kdc_active_realm = state->realm_data; if (inner_body_out != NULL) *inner_body_out = NULL; scratch.data = NULL; krb5_clear_error_message(kdc_context); memset(&empty_keyblock, 0, sizeof(krb5_keyblock)); fast_padata = krb5int_find_pa_data(kdc_context, request->padata, KRB5_PADATA_FX_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 (retval == 0 &&fast_armored_req->armor) { switch (fast_armored_req->armor->armor_type) { case KRB5_FAST_ARMOR_AP_REQUEST: if (tgs_subkey) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(kdc_context, retval, _("Ap-request armor not permitted " "with TGS")); break; } retval = armor_ap_request(state, fast_armored_req->armor); break; default: krb5_set_error_message(kdc_context, KRB5KDC_ERR_PREAUTH_FAILED, _("Unknown FAST armor type %d"), fast_armored_req->armor->armor_type); retval = KRB5KDC_ERR_PREAUTH_FAILED; } } if (retval == 0 && !state->armor_key) { if (tgs_subkey) retval = krb5_c_fx_cf2_simple(kdc_context, tgs_subkey, "subkeyarmor", tgs_session, "ticketarmor", &state->armor_key); else { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(kdc_context, retval, _("No armor key but FAST armored " "request present")); } } if (retval == 0) { krb5_data plaintext; plaintext.length = fast_armored_req->enc_part.ciphertext.length; plaintext.data = malloc(plaintext.length); if (plaintext.data == NULL) retval = ENOMEM; retval = krb5_c_decrypt(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_ENC, NULL, &fast_armored_req->enc_part, &plaintext); if (retval == 0) retval = decode_krb5_fast_req(&plaintext, &fast_req); if (retval == 0 && inner_body_out != NULL) { retval = fetch_asn1_field((unsigned char *)plaintext.data, 1, 2, &scratch); if (retval == 0) { retval = krb5_copy_data(kdc_context, &scratch, &inner_body); } } if (plaintext.data) free(plaintext.data); } cksum = &fast_armored_req->req_checksum; if (retval == 0) retval = krb5_c_verify_checksum(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_REQ_CHKSUM, checksummed_data, cksum, &cksum_valid); if (retval == 0 && !cksum_valid) { retval = KRB5KRB_AP_ERR_MODIFIED; krb5_set_error_message(kdc_context, retval, _("FAST req_checksum invalid; request " "modified")); } if (retval == 0) { if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) { retval = KRB5KDC_ERR_POLICY; krb5_set_error_message(kdc_context, retval, _("Unkeyed checksum used in fast_req")); } } if (retval == 0) { if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0) retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION; } if (retval == 0) cookie_padata = krb5int_find_pa_data(kdc_context, fast_req->req_body->padata, KRB5_PADATA_FX_COOKIE); if (retval == 0) { state->fast_options = fast_req->fast_options; krb5_free_kdc_req( kdc_context, request); *requestptr = fast_req->req_body; fast_req->req_body = NULL; } } else { cookie_padata = krb5int_find_pa_data(kdc_context, 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; } else { new_padata->pa_type = KRB5_PADATA_FX_COOKIE; new_padata->length = cookie_padata->length; new_padata->contents = malloc(new_padata->length); if (new_padata->contents == NULL) { retval = ENOMEM; free(new_padata); } else { memcpy(new_padata->contents, cookie_padata->contents, new_padata->length); state->cookie = new_padata; } } } if (retval == 0 && inner_body_out != NULL) { *inner_body_out = inner_body; inner_body = NULL; } krb5_free_data(kdc_context, inner_body); 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); return retval; }