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; }
static krb5_error_code return_pkinit_kx(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, krb5_pa_data **out_padata) { krb5_error_code ret = 0; krb5_keyblock *session = reply->ticket->enc_part2->session; krb5_keyblock *new_session = NULL; krb5_pa_data *pa = NULL; krb5_enc_data enc; krb5_data *scratch = NULL; *out_padata = NULL; enc.ciphertext.data = NULL; if (!krb5_principal_compare(context, request->client, krb5_anonymous_principal())) return 0; /* * The KDC contribution key needs to be a fresh key of an enctype supported * by the client and server. The existing session key meets these * requirements so we use it. */ ret = krb5_c_fx_cf2_simple(context, session, "PKINIT", encrypting_key, "KEYEXCHANGE", &new_session); if (ret) goto cleanup; ret = encode_krb5_encryption_key( session, &scratch); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, encrypting_key, KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc); if (ret) goto cleanup; memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); scratch = NULL; ret = encode_krb5_enc_data(&enc, &scratch); if (ret) goto cleanup; pa = malloc(sizeof(krb5_pa_data)); if (pa == NULL) { ret = ENOMEM; goto cleanup; } pa->pa_type = KRB5_PADATA_PKINIT_KX; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; scratch->data = NULL; memset(session->contents, 0, session->length); krb5_free_keyblock_contents(context, session); *session = *new_session; new_session->contents = NULL; cleanup: krb5_free_data_contents(context, &enc.ciphertext); krb5_free_keyblock(context, new_session); krb5_free_data(context, scratch); return ret; }
static krb5_error_code fast_armor_ap_request(krb5_context context, struct krb5int_fast_request_state *state, krb5_ccache ccache, krb5_principal target_principal) { 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)); creds.server = target_principal; 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) { TRACE_FAST_ARMOR_CCACHE_KEY(context, &out_creds->keyblock); 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) { TRACE_FAST_ARMOR_KEY(context, armor_key); 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); /* target_principal is owned by caller. */ creds.server = NULL; 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; }
static krb5_error_code armor_ap_request (struct kdc_request_state *state, krb5_fast_armor *armor) { krb5_error_code retval = 0; krb5_auth_context authcontext = NULL; krb5_ticket *ticket = NULL; krb5_keyblock *subkey = NULL; kdc_realm_t *kdc_active_realm = state->realm_data; assert(armor->armor_type == KRB5_FAST_ARMOR_AP_REQUEST); krb5_clear_error_message(kdc_context); retval = krb5_auth_con_init(kdc_context, &authcontext); if (retval == 0) retval = krb5_auth_con_setflags(kdc_context, authcontext, 0); /*disable replay cache*/ retval = krb5_rd_req(kdc_context, &authcontext, &armor->armor_value, NULL /*server*/, kdc_active_realm->realm_keytab, NULL, &ticket); if (retval != 0) { const char * errmsg = krb5_get_error_message(kdc_context, retval); krb5_set_error_message(kdc_context, retval, _("%s while handling ap-request armor"), errmsg); krb5_free_error_message(kdc_context, errmsg); } if (retval == 0) { if (!krb5_principal_compare_any_realm(kdc_context, tgs_server, ticket->server)) { krb5_set_error_message(kdc_context, KRB5KDC_ERR_SERVER_NOMATCH, _("ap-request armor for something other " "than the local TGS")); retval = KRB5KDC_ERR_SERVER_NOMATCH; } } if (retval == 0) { retval = krb5_auth_con_getrecvsubkey(kdc_context, authcontext, &subkey); if (retval != 0 || subkey == NULL) { krb5_set_error_message(kdc_context, KRB5KDC_ERR_POLICY, _("ap-request armor without subkey")); retval = KRB5KDC_ERR_POLICY; } } if (retval == 0) retval = krb5_c_fx_cf2_simple(kdc_context, subkey, "subkeyarmor", ticket->enc_part2->session, "ticketarmor", &state->armor_key); if (ticket) krb5_free_ticket(kdc_context, ticket); if (subkey) krb5_free_keyblock(kdc_context, subkey); if (authcontext) krb5_auth_con_free(kdc_context, authcontext); return retval; }
krb5_error_code kdc_fast_handle_reply_key(struct kdc_request_state *state, krb5_keyblock *existing_key, krb5_keyblock **out_key) { krb5_error_code retval = 0; kdc_realm_t *kdc_active_realm = state->realm_data; if (state->armor_key) retval = krb5_c_fx_cf2_simple(kdc_context, state->strengthen_key, "strengthenkey", existing_key, "replykey", out_key); else retval = krb5_copy_keyblock(kdc_context, existing_key, out_key); return retval; }
krb5_error_code krb5int_fast_reply_key(krb5_context context, krb5_keyblock *strengthen_key, krb5_keyblock *existing_key, krb5_keyblock *out_key) { krb5_keyblock *key = NULL; krb5_error_code retval = 0; krb5_free_keyblock_contents(context, out_key); if (strengthen_key) { retval = krb5_c_fx_cf2_simple(context, strengthen_key, "strengthenkey", existing_key, "replykey", &key); if (retval == 0) { *out_key = *key; free(key); } } else { retval = krb5_copy_keyblock_contents(context, existing_key, out_key); } return retval; }
static krb5_error_code process_preauth(krb5_context context, void *plugin_context, void *request_context, krb5_get_init_creds_opt *opt, preauth_get_client_data_proc get_data_proc, struct _krb5_preauth_client_rock *rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, preauth_get_as_key_proc gak_fct, void *gak_data, krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, krb5_pa_data ***out_padata) { krb5_error_code retval = 0; krb5_enctype enctype = 0; krb5_keyblock *challenge_key = NULL, *armor_key = NULL; krb5_data *etype_data = NULL; krb5int_access kaccess; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; retval = fast_get_armor_key(context, get_data_proc, rock, &armor_key); if (retval || armor_key == NULL) return 0; retval = get_data_proc(context, rock, krb5plugin_preauth_client_get_etype, &etype_data); if (retval == 0) { enctype = *((krb5_enctype *)etype_data->data); if (as_key->length == 0 ||as_key->enctype != enctype) retval = gak_fct(context, request->client, enctype, prompter, prompter_data, salt, s2kparams, as_key, gak_data); } if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; krb5_data scratch; scratch.length = padata->length; scratch.data = (char *) padata->contents; retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval =kaccess.decode_enc_data(&scratch, &enc); scratch.data = NULL; if (retval == 0) { scratch.data = malloc(enc->ciphertext.length); scratch.length = enc->ciphertext.length; if (scratch.data == NULL) retval = ENOMEM; } if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL, enc, &scratch); /* * Per draft 11 of the preauth framework, the client MAY but is not * required to actually check the timestamp from the KDC other than to * confirm it decrypts. This code does not perform that check. */ if (scratch.data) krb5_free_data_contents(context, &scratch); if (retval == 0) fast_set_kdc_verified(context, get_data_proc, rock); if (enc) kaccess.free_enc_data(context, enc); } else if (retval == 0) { /*No padata; we send*/ krb5_enc_data enc; krb5_pa_data *pa = NULL; krb5_pa_data **pa_array = NULL; krb5_data *encoded_ts = NULL; krb5_pa_enc_ts ts; enc.ciphertext.data = NULL; retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = kaccess.encode_enc_ts(&ts, &encoded_ts); if (retval == 0) retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = kaccess.encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, encoded_ts, &enc); if (encoded_ts) krb5_free_data(context, encoded_ts); encoded_ts = NULL; if (retval == 0) { retval = kaccess.encode_enc_data(&enc, &encoded_ts); krb5_free_data_contents(context, &enc.ciphertext); } if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa_array = calloc(2, sizeof(krb5_pa_data *)); if (pa_array == NULL) retval = ENOMEM; } if (retval == 0) { pa->length = encoded_ts->length; pa->contents = (unsigned char *) encoded_ts->data; pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; free(encoded_ts); encoded_ts = NULL; pa_array[0] = pa; pa = NULL; *out_padata = pa_array; pa_array = NULL; } if (pa) free(pa); if (encoded_ts) krb5_free_data(context, encoded_ts); if (pa_array) free(pa_array); } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (armor_key) krb5_free_keyblock(context, armor_key); if (etype_data != NULL) get_data_proc(context, rock, krb5plugin_preauth_client_free_etype, &etype_data); return retval; }
static krb5_error_code kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data, preauth_get_entry_data_proc get_entry_proc, void *pa_module_context, void **pa_request_context, krb5_data **e_data, krb5_authdata ***authz_data) { krb5_error_code retval = 0; krb5_timestamp now; krb5_enc_data *enc = NULL; krb5_data scratch, plain; krb5_keyblock *armor_key = NULL; krb5_pa_enc_ts *ts = NULL; krb5int_access kaccess; krb5_keyblock *client_keys = NULL; krb5_data *client_data = NULL; krb5_keyblock *challenge_key = NULL; int i = 0; plain.data = NULL; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key); if (retval == 0 &&armor_key == NULL) { retval = ENOENT; krb5_set_error_message(context, ENOENT, "Encrypted Challenge used outside of FAST tunnel"); } scratch.data = (char *) data->contents; scratch.length = data->length; if (retval == 0) retval = kaccess.decode_enc_data(&scratch, &enc); if (retval == 0) { plain.data = malloc(enc->ciphertext.length); plain.length = enc->ciphertext.length; if (plain.data == NULL) retval = ENOMEM; } if (retval == 0) retval = get_entry_proc(context, request, client, krb5plugin_preauth_keys, &client_data); if (retval == 0) { client_keys = (krb5_keyblock *) client_data->data; for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) { retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", &client_keys[i], "challengelongterm", &challenge_key); if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, NULL, enc, &plain); if (challenge_key) krb5_free_keyblock(context, challenge_key); challenge_key = NULL; if (retval == 0) break; /*We failed to decrypt. Try next key*/ retval = 0; krb5_free_keyblock_contents(context, &client_keys[i]); } if (client_keys[i].enctype == 0) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(context, retval, "Incorrect password in encrypted challenge"); } else { /*not run out of keys*/ int j; assert (retval == 0); for (j = i+1; client_keys[j].enctype; j++) krb5_free_keyblock_contents(context, &client_keys[j]); } } if (retval == 0) retval = kaccess.decode_enc_ts(&plain, &ts); if (retval == 0) retval = krb5_timeofday(context, &now); if (retval == 0) { if (labs(now-ts->patimestamp) < context->clockskew) { enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; /* * If this fails, we won't generate a reply to the client. That * may cause the client to fail, but at this point the KDC has * considered this a success, so the return value is ignored. */ fast_kdc_replace_reply_key(context, get_entry_proc, request); krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor", &client_keys[i], "challengelongterm", (krb5_keyblock **) pa_request_context); } else { /*skew*/ retval = KRB5KRB_AP_ERR_SKEW; } } if (client_keys) { if (client_keys[i].enctype) krb5_free_keyblock_contents(context, &client_keys[i]); krb5_free_data(context, client_data); } if (armor_key) krb5_free_keyblock(context, armor_key); if (plain.data) free(plain.data); if (enc) kaccess.free_enc_data(context, enc); if (ts) kaccess.free_enc_ts(context, ts); 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; }
static void ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_verify_respond_fn respond, void *arg) { krb5_error_code retval = 0; krb5_timestamp now; krb5_enc_data *enc = NULL; krb5_data scratch, plain; krb5_keyblock *armor_key = cb->fast_armor(context, rock); krb5_pa_enc_ts *ts = NULL; krb5_keyblock *client_keys = NULL; krb5_keyblock *challenge_key = NULL; krb5_keyblock *kdc_challenge_key; krb5_kdcpreauth_modreq modreq = NULL; int i = 0; plain.data = NULL; if (armor_key == NULL) { retval = ENOENT; krb5_set_error_message(context, ENOENT, _("Encrypted Challenge used outside of FAST " "tunnel")); } scratch.data = (char *) data->contents; scratch.length = data->length; if (retval == 0) retval = decode_krb5_enc_data(&scratch, &enc); if (retval == 0) { plain.data = malloc(enc->ciphertext.length); plain.length = enc->ciphertext.length; if (plain.data == NULL) retval = ENOMEM; } if (retval == 0) retval = cb->client_keys(context, rock, &client_keys); if (retval == 0) { for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) { retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", &client_keys[i], "challengelongterm", &challenge_key); if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, NULL, enc, &plain); if (challenge_key) krb5_free_keyblock(context, challenge_key); challenge_key = NULL; if (retval == 0) break; /*We failed to decrypt. Try next key*/ retval = 0; } if (client_keys[i].enctype == 0) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(context, retval, _("Incorrect password in encrypted " "challenge")); } } if (retval == 0) retval = decode_krb5_pa_enc_ts(&plain, &ts); if (retval == 0) retval = krb5_timeofday(context, &now); if (retval == 0) { if (labs(now-ts->patimestamp) < context->clockskew) { enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; /* * If this fails, we won't generate a reply to the client. That * may cause the client to fail, but at this point the KDC has * considered this a success, so the return value is ignored. */ if (krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor", &client_keys[i], "challengelongterm", &kdc_challenge_key) == 0) modreq = (krb5_kdcpreauth_modreq)kdc_challenge_key; } else { /*skew*/ retval = KRB5KRB_AP_ERR_SKEW; } } cb->free_keys(context, rock, client_keys); if (plain.data) free(plain.data); if (enc) krb5_free_enc_data(context, enc); if (ts) krb5_free_pa_enc_ts(context, ts); (*respond)(arg, retval, modreq, NULL, NULL); }
static krb5_error_code ec_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***out_padata) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = NULL, *armor_key, *as_key; armor_key = cb->fast_armor(context, rock); if (armor_key == NULL) return ENOENT; retval = cb->get_as_key(context, rock, &as_key); if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; krb5_data scratch; scratch.length = padata->length; scratch.data = (char *) padata->contents; retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = decode_krb5_enc_data(&scratch, &enc); scratch.data = NULL; if (retval == 0) { scratch.data = malloc(enc->ciphertext.length); scratch.length = enc->ciphertext.length; if (scratch.data == NULL) retval = ENOMEM; } if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL, enc, &scratch); /* * Per draft 11 of the preauth framework, the client MAY but is not * required to actually check the timestamp from the KDC other than to * confirm it decrypts. This code does not perform that check. */ if (scratch.data) krb5_free_data_contents(context, &scratch); /* If we had a callback to assert that the KDC is verified, we would * call it here. */ if (enc) krb5_free_enc_data(context, enc); } else if (retval == 0) { /*No padata; we send*/ krb5_enc_data enc; krb5_pa_data **pa = NULL; krb5_data *encoded_ts = NULL; krb5_pa_enc_ts ts; enc.ciphertext.data = NULL; /* Use the timestamp from the preauth-required error if possible. * This time should always be secured by the FAST channel. */ retval = cb->get_preauth_time(context, rock, FALSE, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = encode_krb5_pa_enc_ts(&ts, &encoded_ts); if (retval == 0) retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = krb5_encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, encoded_ts, &enc); if (encoded_ts) krb5_free_data(context, encoded_ts); encoded_ts = NULL; if (retval == 0) { retval = encode_krb5_enc_data(&enc, &encoded_ts); krb5_free_data_contents(context, &enc.ciphertext); } if (retval == 0) { pa = calloc(2, sizeof(krb5_pa_data *)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa[0] = calloc(1, sizeof(krb5_pa_data)); if (pa[0] == NULL) retval = ENOMEM; } if (retval == 0) { pa[0]->length = encoded_ts->length; pa[0]->contents = (unsigned char *) encoded_ts->data; pa[0]->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; encoded_ts->data = NULL; *out_padata = pa; pa = NULL; } free(pa); krb5_free_data(context, encoded_ts); } if (challenge_key) krb5_free_keyblock(context, challenge_key); return retval; }