krb5_error_code krb5_dbe_find_enctype(krb5_context kcontext, krb5_db_entry * dbentp, krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, krb5_key_data ** kdatap) { krb5_int32 start = 0; return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, kvno, kdatap); }
/* * Construct the secure cookie encryption key for the given local-realm TGT * entry, kvno, and client principal. The cookie key is derived from the first * TGT key for the given kvno, using the concatenation of "COOKIE" and the * unparsed client principal name as input. If kvno is 0, the highest current * kvno of the TGT is used. If kvno_out is not null, *kvno_out is set to the * kvno used. */ static krb5_error_code get_cookie_key(krb5_context context, krb5_db_entry *tgt, krb5_kvno kvno, krb5_const_principal client_princ, krb5_keyblock **key_out, krb5_kvno *kvno_out) { krb5_error_code ret; krb5_key_data *kd; krb5_keyblock kb; krb5_data d; krb5_int32 start = 0; char *princstr = NULL, *derive_input = NULL; *key_out = NULL; memset(&kb, 0, sizeof(kb)); /* Find the first krbtgt key with the specified kvno. */ ret = krb5_dbe_search_enctype(context, tgt, &start, -1, -1, kvno, &kd); if (ret) goto cleanup; /* Decrypt the key. */ ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL); if (ret) goto cleanup; /* Construct the input string and derive the cookie key. */ ret = krb5_unparse_name(context, client_princ, &princstr); if (ret) goto cleanup; if (asprintf(&derive_input, "COOKIE%s", princstr) < 0) { ret = ENOMEM; goto cleanup; } d = string2data(derive_input); ret = krb5_c_derive_prfplus(context, &kb, &d, ENCTYPE_NULL, key_out); if (kvno_out != NULL) *kvno_out = kd->key_data_kvno; cleanup: krb5_free_keyblock_contents(context, &kb); krb5_free_unparsed_name(context, princstr); free(derive_input); return ret; }
static void enc_ts_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_verify_respond_fn respond, void *arg) { krb5_pa_enc_ts * pa_enc = 0; krb5_error_code retval; krb5_data scratch; krb5_data enc_ts_data; krb5_enc_data *enc_data = 0; krb5_keyblock key; krb5_key_data * client_key; krb5_int32 start; krb5_timestamp timenow; krb5_error_code decrypt_err = 0; scratch.data = (char *)pa->contents; scratch.length = pa->length; enc_ts_data.data = 0; if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0) goto cleanup; enc_ts_data.length = enc_data->ciphertext.length; if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL) goto cleanup; start = 0; decrypt_err = 0; while (1) { if ((retval = krb5_dbe_search_enctype(context, rock->client, &start, enc_data->enctype, -1, 0, &client_key))) goto cleanup; if ((retval = krb5_dbe_decrypt_key_data(context, NULL, client_key, &key, NULL))) goto cleanup; key.enctype = enc_data->enctype; retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, 0, enc_data, &enc_ts_data); krb5_free_keyblock_contents(context, &key); if (retval == 0) break; else decrypt_err = retval; } if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0) goto cleanup; if ((retval = krb5_timeofday(context, &timenow)) != 0) goto cleanup; if (labs(timenow - pa_enc->patimestamp) > context->clockskew) { retval = KRB5KRB_AP_ERR_SKEW; goto cleanup; } setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH); retval = 0; cleanup: if (enc_data) { krb5_free_data_contents(context, &enc_data->ciphertext); free(enc_data); } krb5_free_data_contents(context, &enc_ts_data); if (pa_enc) free(pa_enc); /* * If we get NO_MATCHING_KEY and decryption previously failed, and * we failed to find any other keys of the correct enctype after * that failed decryption, it probably means that the password was * incorrect. */ if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0) retval = decrypt_err; (*respond)(arg, retval, NULL, NULL, NULL); }