}
/*
- * Create a CAMMAC for contents, using enc_tkt and the first key from krbtgt
- * for the KDC verifier. Set *cammac_out to a single-element authdata list
- * containing the CAMMAC inside an IF-RELEVANT container.
+ * Create a CAMMAC for contents, using enc_tkt and tgt_key for the KDC
+ * verifier. tgt_key must be the decrypted first key data entry in tgt. Set
+ * *cammac_out to a single-element authdata list containing the CAMMAC inside
+ * an IF-RELEVANT container.
*/
krb5_error_code
cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt,
- krb5_keyblock *server_key, krb5_db_entry *krbtgt,
- krb5_authdata **contents, krb5_authdata ***cammac_out)
+ krb5_keyblock *server_key, krb5_db_entry *tgt,
+ krb5_keyblock *tgt_key, krb5_authdata **contents,
+ krb5_authdata ***cammac_out)
{
krb5_error_code ret;
krb5_data *der_authdata = NULL, *der_enctkt = NULL, *der_cammac = NULL;
krb5_authdata ad, *list[2];
krb5_cammac cammac;
krb5_verifier_mac kdc_verifier, svc_verifier;
- krb5_key_data *kd;
krb5_keyblock tgtkey;
krb5_checksum kdc_cksum, svc_cksum;
memset(&kdc_cksum, 0, sizeof(kdc_cksum));
memset(&svc_cksum, 0, sizeof(svc_cksum));
- /* Fetch the first krbtgt key for the KDC verifier. */
- ret = krb5_dbe_find_enctype(context, krbtgt, -1, -1, 0, &kd);
- if (ret)
- goto cleanup;
- ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
- if (ret)
- goto cleanup;
-
/* Checksum the reply with contents as authdata for the KDC verifier. */
ret = encode_kdcver_encpart(enc_tkt, contents, &der_enctkt);
if (ret)
goto cleanup;
- ret = krb5_c_make_checksum(context, 0, &tgtkey, KRB5_KEYUSAGE_CAMMAC,
+ ret = krb5_c_make_checksum(context, 0, tgt_key, KRB5_KEYUSAGE_CAMMAC,
der_enctkt, &kdc_cksum);
if (ret)
goto cleanup;
kdc_verifier.princ = NULL;
- kdc_verifier.kvno = kd->key_data_kvno;
+ kdc_verifier.kvno = tgt->key_data[0].key_data_kvno;
kdc_verifier.enctype = ENCTYPE_NULL;
kdc_verifier.checksum = kdc_cksum;
return ret;
}
-/* Return true if cammac's KDC verifier is valid for enc_tkt, using krbtgt to
- * retrieve the TGT key indicated by the verifier. */
+/*
+ * Return true if cammac's KDC verifier is valid for enc_tkt, using tgt to
+ * retrieve the TGT key indicated by the verifier. tgt_key must be the
+ * decrypted first key data entry in tgt.
+ */
krb5_boolean
cammac_check_kdcver(krb5_context context, krb5_cammac *cammac,
- krb5_enc_tkt_part *enc_tkt, krb5_db_entry *krbtgt)
+ krb5_enc_tkt_part *enc_tkt, krb5_db_entry *tgt,
+ krb5_keyblock *tgt_key)
{
krb5_verifier_mac *ver = cammac->kdc_verifier;
krb5_key_data *kd;
- krb5_keyblock tgtkey;
+ krb5_keyblock tgtkey, *key;
krb5_boolean valid = FALSE;
krb5_data *der_enctkt = NULL;
/* Fetch the krbtgt key indicated by the KDC verifier. Only allow the
* first krbtgt key of the specified kvno. */
- if (krb5_dbe_find_enctype(context, krbtgt, -1, -1, ver->kvno, &kd) != 0)
- goto cleanup;
- if (krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL) != 0)
- goto cleanup;
+ if (ver->kvno == tgt->key_data[0].key_data_kvno) {
+ key = tgt_key;
+ } else {
+ if (krb5_dbe_find_enctype(context, tgt, -1, -1, ver->kvno, &kd) != 0)
+ goto cleanup;
+ if (krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL) != 0)
+ goto cleanup;
+ key = &tgtkey;
+ }
if (ver->enctype != ENCTYPE_NULL && tgtkey.enctype != ver->enctype)
goto cleanup;
* elements as authdata. */
if (encode_kdcver_encpart(enc_tkt, cammac->elements, &der_enctkt) != 0)
goto cleanup;
- (void)krb5_c_verify_checksum(context, &tgtkey, KRB5_KEYUSAGE_CAMMAC,
+ (void)krb5_c_verify_checksum(context, key, KRB5_KEYUSAGE_CAMMAC,
der_enctkt, &ver->checksum, &valid);
cleanup:
static krb5_error_code
prepare_error_as(struct kdc_request_state *, krb5_kdc_req *, krb5_db_entry *,
- int, krb5_pa_data **, krb5_boolean, krb5_principal,
- krb5_data **, const char *);
+ krb5_keyblock *, int, krb5_pa_data **, krb5_boolean,
+ krb5_principal, krb5_data **, const char *);
/* Determine the key-expiration value according to RFC 4120 section 5.4.2. */
static krb5_timestamp
krb5_enc_tkt_part enc_tkt_reply;
krb5_enc_kdc_rep_part reply_encpart;
krb5_ticket ticket_reply;
+ krb5_keyblock local_tgt_key;
krb5_keyblock server_keyblock;
krb5_keyblock client_keyblock;
krb5_db_entry *client;
goto egress;
}
- errcode = handle_authdata(kdc_context,
- state->c_flags,
- state->client,
- state->server,
- NULL,
- state->local_tgt,
- &state->client_keyblock,
- &state->server_keyblock,
- NULL,
- state->req_pkt,
- state->request,
- NULL, /* for_user_princ */
- NULL, /* enc_tkt_request */
- state->auth_indicators,
- &state->enc_tkt_reply);
+ errcode = handle_authdata(kdc_context, state->c_flags, state->client,
+ state->server, NULL, state->local_tgt,
+ &state->local_tgt_key, &state->client_keyblock,
+ &state->server_keyblock, NULL, state->req_pkt,
+ state->request, NULL, NULL,
+ state->auth_indicators, &state->enc_tkt_reply);
if (errcode) {
krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
errcode);
errcode = KRB_ERR_GENERIC;
errcode = prepare_error_as(state->rstate, state->request,
- state->local_tgt, errcode,
- state->e_data, state->typed_e_data,
+ state->local_tgt, &state->local_tgt_key,
+ errcode, state->e_data,
+ state->typed_e_data,
((state->client != NULL) ?
state->client->princ : NULL),
&response, state->status);
if (state->enc_tkt_reply.authorization_data != NULL)
krb5_free_authdata(kdc_context,
state->enc_tkt_reply.authorization_data);
+ if (state->local_tgt_key.contents != NULL)
+ krb5_free_keyblock_contents(kdc_context, &state->local_tgt_key);
if (state->server_keyblock.contents != NULL)
krb5_free_keyblock_contents(kdc_context, &state->server_keyblock);
if (state->client_keyblock.contents != NULL)
errcode = get_local_tgt(kdc_context, &state->request->server->realm,
state->server, &state->local_tgt,
- &state->local_tgt_storage);
+ &state->local_tgt_storage, &state->local_tgt_key);
if (errcode) {
state->status = "GET_LOCAL_TGT";
goto errout;
}
errcode = kdc_fast_read_cookie(kdc_context, state->rstate, state->request,
- state->local_tgt);
+ state->local_tgt, &state->local_tgt_key);
if (errcode) {
state->status = "READ_COOKIE";
goto errout;
static krb5_error_code
prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request,
- krb5_db_entry *local_tgt, int error, krb5_pa_data **e_data_in,
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
+ int error, krb5_pa_data **e_data_in,
krb5_boolean typed_e_data, krb5_principal canon_client,
krb5_data **response, const char *status)
{
return ENOMEM;
memcpy(e_data, e_data_in, count * sizeof(*e_data));
retval = kdc_fast_make_cookie(kdc_context, rstate, local_tgt,
- request->client, &cookie);
+ local_tgt_key, request->client,
+ &cookie);
e_data[count] = cookie;
}
krb5_error_code retval = 0;
krb5_keyblock server_keyblock, *encrypting_key;
krb5_timestamp kdc_time, authtime = 0;
- krb5_keyblock session_key;
+ krb5_keyblock session_key, local_tgt_key;
krb5_keyblock *reply_key = NULL;
krb5_key_data *server_key;
krb5_principal cprinc = NULL, sprinc = NULL, altcprinc = NULL;
memset(&ticket_reply, 0, sizeof(ticket_reply));
memset(&enc_tkt_reply, 0, sizeof(enc_tkt_reply));
memset(&server_keyblock, 0, sizeof(server_keyblock));
+ memset(&local_tgt_key, 0, sizeof(local_tgt_key));
session_key.contents = NULL;
/* Save pointer to client-requested service principal, in case of
}
errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server,
- &local_tgt, &local_tgt_storage);
+ &local_tgt, &local_tgt_storage, &local_tgt_key);
if (errcode) {
status = "GET_LOCAL_TGT";
goto cleanup;
* requests (where the client didn't authenticate). */
if (s4u_x509_user == NULL) {
errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
- &auth_indicators);
+ &local_tgt_key, &auth_indicators);
if (errcode) {
status = "GET_AUTH_INDICATORS";
goto cleanup;
}
errcode = handle_authdata(kdc_context, c_flags, client, server,
- header_server, local_tgt,
+ header_server, local_tgt, &local_tgt_key,
subkey != NULL ? subkey :
header_ticket->enc_part2->session,
encrypting_key, /* U2U or server key */
krb5_db_free_principal(kdc_context, header_server);
krb5_db_free_principal(kdc_context, client);
krb5_db_free_principal(kdc_context, local_tgt_storage);
+ if (local_tgt_key.contents != NULL)
+ krb5_free_keyblock_contents(kdc_context, &local_tgt_key);
if (session_key.contents != NULL)
krb5_free_keyblock_contents(kdc_context, &session_key);
if (newtransited)
}
/*
- * 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.
+ * Derive the secure cookie encryption key from tgt_key and client_princ. The
+ * cookie key is derived with PRF+ using the concatenation of "COOKIE" and the
+ * unparsed client principal name as input.
*/
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)
+derive_cookie_key(krb5_context context, krb5_keyblock *tgt_key,
+ krb5_const_principal client_princ, krb5_keyblock **key_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);
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;
+ ret = krb5_c_derive_prfplus(context, tgt_key, &d, ENCTYPE_NULL, key_out);
cleanup:
- krb5_free_keyblock_contents(context, &kb);
krb5_free_unparsed_name(context, princstr);
free(derive_input);
return ret;
}
+/* Derive the cookie key for the specified kvno in tgt. tgt_key must be the
+ * decrypted first key data entry in tgt. */
+static krb5_error_code
+get_cookie_key(krb5_context context, krb5_db_entry *tgt,
+ krb5_keyblock *tgt_key, krb5_kvno kvno,
+ krb5_const_principal client_princ, krb5_keyblock **key_out)
+{
+ krb5_error_code ret;
+ krb5_keyblock storage, *key;
+ krb5_key_data *kd;
+
+ *key_out = NULL;
+ memset(&storage, 0, sizeof(storage));
+
+ if (kvno == tgt->key_data[0].key_data_kvno) {
+ /* Use the already-decrypted first key. */
+ key = tgt_key;
+ } else {
+ /* The cookie used an older TGT key; find and decrypt it. */
+ ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
+ if (ret)
+ return ret;
+ ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &storage, NULL);
+ if (ret)
+ return ret;
+ key = &storage;
+ }
+
+ ret = derive_cookie_key(context, key, client_princ, key_out);
+ krb5_free_keyblock_contents(context, &storage);
+ return ret;
+}
+
/* Return true if there is any overlap between padata types in cpadata
* (from the cookie) and rpadata (from the request). */
static krb5_boolean
*/
krb5_error_code
kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state,
- krb5_kdc_req *req, krb5_db_entry *local_tgt)
+ krb5_kdc_req *req, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key)
{
krb5_error_code ret;
krb5_secure_cookie *cookie = NULL;
/* Extract the kvno and generate the corresponding cookie key. */
kvno = load_32_be(pa->contents + 4);
- ret = get_cookie_key(context, local_tgt, kvno, req->client, &key, NULL);
+ ret = get_cookie_key(context, local_tgt, local_tgt_key, kvno, req->client,
+ &key);
if (ret)
goto cleanup;
* trivial "MIT" cookie if no values are set. */
krb5_error_code
kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
- krb5_db_entry *local_tgt,
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
krb5_const_principal client_princ,
krb5_pa_data **cookie_out)
{
krb5_timestamp now;
krb5_enc_data enc;
krb5_data *der_cookie = NULL;
- krb5_kvno kvno;
size_t ctlen;
*cookie_out = NULL;
/* Make a trivial cookie if there are no contents to marshal or we don't
* have a TGT entry to encrypt them. */
- if (contents == NULL || *contents == NULL || local_tgt == NULL)
+ if (contents == NULL || *contents == NULL || local_tgt_key == NULL)
return make_padata(KRB5_PADATA_FX_COOKIE, "MIT", 3, cookie_out);
- ret = get_cookie_key(context, local_tgt, 0, client_princ, &key, &kvno);
+ ret = derive_cookie_key(context, local_tgt_key, client_princ, &key);
if (ret)
goto cleanup;
ret = k5_alloc_pa_data(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length,
&pa);
memcpy(pa->contents, "MIT1", 4);
- store_32_be(kvno, pa->contents + 4);
+ store_32_be(local_tgt->key_data[0].key_data_kvno, pa->contents + 4);
memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
*cookie_out = pa;
static krb5_error_code
verify_signedpath_checksum(krb5_context context, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key,
krb5_enc_tkt_part *enc_tkt_part,
krb5_principal *deleg_path,
krb5_pa_data **method_data, krb5_checksum *cksum,
if (ret)
return ret;
- /* There is no kvno in AD-SIGNTICKET, so try the last three versions. */
- kvno = 0;
- tries = 3;
- do {
- /* Get the first local tgt key of this kvno (highest kvno for the first
- * iteration). */
- ret = krb5_dbe_find_enctype(context, local_tgt, -1, -1, kvno, &kd);
- if (ret) {
- ret = 0;
- break;
+ ret = krb5_c_verify_checksum(context, local_tgt_key,
+ KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum,
+ &valid);
+ if (ret || !valid) {
+ /* There is no kvno in AD-SIGNTICKET, so try two previous versions. */
+ kvno = local_tgt->key_data[0].key_data_kvno - 1;
+ for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
+ /* Get the first local tgt key of this kvno. */
+ ret = krb5_dbe_find_enctype(context, local_tgt, -1, -1, kvno, &kd);
+ if (ret) {
+ ret = 0;
+ break;
+ }
+ ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
+ if (ret)
+ break;
+
+ ret = krb5_c_verify_checksum(context, &tgtkey,
+ KRB5_KEYUSAGE_AD_SIGNEDPATH, data,
+ cksum, &valid);
+ krb5_free_keyblock_contents(context, &tgtkey);
+ if (!ret && valid)
+ break;
}
- ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
- if (ret)
- break;
-
- ret = krb5_c_verify_checksum(context, &tgtkey,
- KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum,
- &valid);
- krb5_free_keyblock_contents(context, &tgtkey);
- if (!ret && valid)
- break;
-
- /* Try the next lower kvno on the next iteration. */
- kvno = kd->key_data_kvno - 1;
- } while (--tries > 0 && kvno > 0);
+ }
*valid_out = valid;
krb5_free_data(context, data);
static krb5_error_code
verify_signedpath(krb5_context context, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key,
krb5_enc_tkt_part *enc_tkt_part,
krb5_principal **delegated_out, krb5_boolean *pathsigned_out)
{
goto cleanup;
}
- ret = verify_signedpath_checksum(context, local_tgt, enc_tkt_part,
- sp->delegated, sp->method_data,
- &sp->checksum, pathsigned_out);
+ ret = verify_signedpath_checksum(context, local_tgt, local_tgt_key,
+ enc_tkt_part, sp->delegated,
+ sp->method_data, &sp->checksum,
+ pathsigned_out);
if (ret)
goto cleanup;
static krb5_error_code
make_signedpath_checksum(krb5_context context,
krb5_const_principal for_user_princ,
- krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key,
krb5_enc_tkt_part *enc_tkt_part,
krb5_principal *deleg_path,
krb5_pa_data **method_data, krb5_checksum *cksum_out,
krb5_error_code ret;
krb5_data *data = NULL;
krb5_const_principal client;
- krb5_key_data *kd;
- krb5_keyblock tgtkey;
- memset(&tgtkey, 0, sizeof(tgtkey));
memset(cksum_out, 0, sizeof(*cksum_out));
*enctype_out = ENCTYPE_NULL;
client = (for_user_princ != NULL) ? for_user_princ : enc_tkt_part->client;
- /* Get the first local tgt key of the highest kvno. */
- ret = krb5_dbe_find_enctype(context, local_tgt, -1, -1, 0, &kd);
- if (ret)
- goto cleanup;
- ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
- if (ret)
- goto cleanup;
-
ret = make_signedpath_data(context, client, enc_tkt_part->times.authtime,
deleg_path, method_data,
enc_tkt_part->authorization_data, &data);
if (ret)
- goto cleanup;
+ return ret;
- ret = krb5_c_make_checksum(context, 0, &tgtkey,
+ ret = krb5_c_make_checksum(context, 0, local_tgt_key,
KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum_out);
- *enctype_out = tgtkey.enctype;
-
-cleanup:
krb5_free_data(context, data);
- krb5_free_keyblock_contents(context, &tgtkey);
- return ret;
+ if (ret)
+ return ret;
+
+ *enctype_out = local_tgt_key->enctype;
+ return 0;
}
static krb5_error_code
make_signedpath(krb5_context context, krb5_const_principal for_user_princ,
- krb5_principal server, krb5_db_entry *local_tgt,
+ krb5_principal server, krb5_keyblock *local_tgt_key,
krb5_principal *deleg_path, krb5_enc_tkt_part *enc_tkt_reply)
{
krb5_error_code ret;
sp.delegated[count] = NULL;
sp.method_data = NULL;
- ret = make_signedpath_checksum(context, for_user_princ, local_tgt,
+ ret = make_signedpath_checksum(context, for_user_princ, local_tgt_key,
enc_tkt_reply, sp.delegated, sp.method_data,
&sp.checksum, &sp.enctype);
if (ret) {
static krb5_error_code
handle_signticket(krb5_context context, unsigned int flags,
krb5_db_entry *client, krb5_db_entry *server,
- krb5_db_entry *local_tgt, krb5_kdc_req *req,
- krb5_const_principal for_user_princ,
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
+ krb5_kdc_req *req, krb5_const_principal for_user_princ,
krb5_enc_tkt_part *enc_tkt_req,
krb5_enc_tkt_part *enc_tkt_reply)
{
*/
if (req->msg_type == KRB5_TGS_REQ &&
!only_pac_p(context, enc_tkt_req->authorization_data)) {
- ret = verify_signedpath(context, local_tgt, enc_tkt_req, &deleg_path,
- &signed_path);
+ ret = verify_signedpath(context, local_tgt, local_tgt_key, enc_tkt_req,
+ &deleg_path, &signed_path);
if (ret)
goto cleanup;
!is_cross_tgs_principal(server->princ) &&
!only_pac_p(context, enc_tkt_reply->authorization_data)) {
ret = make_signedpath(context, for_user_princ,
- s4u2proxy ? client->princ : NULL, local_tgt,
+ s4u2proxy ? client->princ : NULL, local_tgt_key,
deleg_path, enc_tkt_reply);
if (ret)
goto cleanup;
static krb5_error_code
add_auth_indicators(krb5_context context, krb5_data *const *auth_indicators,
krb5_keyblock *server_key, krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
krb5_enc_tkt_part *enc_tkt_reply)
{
krb5_error_code ret;
list[1] = NULL;
/* Wrap the list in CAMMAC and IF-RELEVANT containers. */
- ret = cammac_create(context, enc_tkt_reply, server_key, krbtgt, list,
- &cammac);
+ ret = cammac_create(context, enc_tkt_reply, server_key, krbtgt, krbtgt_key,
+ list, &cammac);
if (ret)
goto cleanup;
* enc_tkt. */
krb5_error_code
get_auth_indicators(krb5_context context, krb5_enc_tkt_part *enc_tkt,
- krb5_db_entry *local_tgt, krb5_data ***indicators_out)
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
+ krb5_data ***indicators_out)
{
krb5_error_code ret;
krb5_authdata **cammacs = NULL, **adp;
ret = decode_krb5_cammac(&der_cammac, &cammac);
if (ret)
goto cleanup;
- if (cammac_check_kdcver(context, cammac, enc_tkt, local_tgt)) {
+ if (cammac_check_kdcver(context, cammac, enc_tkt, local_tgt,
+ local_tgt_key)) {
ret = authind_extract(context, cammac->elements, &indicators);
if (ret)
goto cleanup;
handle_authdata(krb5_context context, unsigned int flags,
krb5_db_entry *client, krb5_db_entry *server,
krb5_db_entry *header_server, krb5_db_entry *local_tgt,
- krb5_keyblock *client_key, krb5_keyblock *server_key,
- krb5_keyblock *header_key, krb5_data *req_pkt,
- krb5_kdc_req *req, krb5_const_principal for_user_princ,
+ krb5_keyblock *local_tgt_key, krb5_keyblock *client_key,
+ krb5_keyblock *server_key, krb5_keyblock *header_key,
+ krb5_data *req_pkt, krb5_kdc_req *req,
+ krb5_const_principal for_user_princ,
krb5_enc_tkt_part *enc_tkt_req,
krb5_data *const *auth_indicators,
krb5_enc_tkt_part *enc_tkt_reply)
if (auth_indicators != NULL && *auth_indicators != NULL &&
!isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED)) {
ret = add_auth_indicators(context, auth_indicators, server_key,
- local_tgt, enc_tkt_reply);
+ local_tgt, local_tgt_key, enc_tkt_reply);
if (ret)
return ret;
}
/* Validate and insert AD-SIGNTICKET authdata. This must happen last
* since it contains a signature over the other authdata. */
ret = handle_signticket(context, flags, client, server, local_tgt,
- req, for_user_princ, enc_tkt_req,
- enc_tkt_reply);
+ local_tgt_key, req, for_user_princ,
+ enc_tkt_req, enc_tkt_reply);
if (ret)
return ret;
}
/*
* If candidate is the local TGT for realm, set *alias_out to candidate and
* *storage_out to NULL. Otherwise, load the local TGT into *storage_out and
- * set *alias_out to *storage_out.
+ * set *alias_out to *storage_out. In either case, set *key_out to the
+ * decrypted first key of the local TGT.
*
* In the future we might generalize this to a small per-request principal
* cache. For now, it saves a load operation in the common case where the AS
krb5_error_code
get_local_tgt(krb5_context context, const krb5_data *realm,
krb5_db_entry *candidate, krb5_db_entry **alias_out,
- krb5_db_entry **storage_out)
+ krb5_db_entry **storage_out, krb5_keyblock *key_out)
{
krb5_error_code ret;
krb5_principal princ;
- krb5_db_entry *tgt;
+ krb5_db_entry *storage = NULL, *tgt;
*alias_out = NULL;
*storage_out = NULL;
+ memset(key_out, 0, sizeof(*key_out));
ret = krb5_build_principal_ext(context, &princ, realm->length, realm->data,
KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
realm->length, realm->data, 0);
if (ret)
- return ret;
+ goto cleanup;
if (!krb5_principal_compare(context, candidate->princ, princ)) {
- ret = krb5_db_get_principal(context, princ, 0, &tgt);
- if (!ret)
- *storage_out = *alias_out = tgt;
+ ret = krb5_db_get_principal(context, princ, 0, &storage);
+ if (ret)
+ goto cleanup;
+ tgt = storage;
} else {
- *alias_out = candidate;
+ tgt = candidate;
}
+ if (tgt->n_key_data == 0) {
+ ret = KRB5_KDB_NO_MATCHING_KEY;
+ goto cleanup;
+ }
+ ret = krb5_dbe_decrypt_key_data(context, NULL, &tgt->key_data[0], key_out,
+ NULL);
+ if (ret)
+ goto cleanup;
+
+ *alias_out = tgt;
+ *storage_out = storage;
+ storage = NULL;
+
+cleanup:
+ krb5_db_free_principal(context, storage);
krb5_free_principal(context, princ);
return ret;
}
krb5_error_code
get_local_tgt(krb5_context context, const krb5_data *realm,
krb5_db_entry *candidate, krb5_db_entry **alias_out,
- krb5_db_entry **storage_out);
+ krb5_db_entry **storage_out, krb5_keyblock *kb_out);
int
validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry,
/* cammac.c */
krb5_error_code
cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt_reply,
- krb5_keyblock *server_key, krb5_db_entry *krbtgt,
- krb5_authdata **contents, krb5_authdata ***cammac_out);
+ krb5_keyblock *server_key, krb5_db_entry *tgt,
+ krb5_keyblock *tgt_key, krb5_authdata **contents,
+ krb5_authdata ***cammac_out);
krb5_boolean
cammac_check_kdcver(krb5_context context, krb5_cammac *cammac,
- krb5_enc_tkt_part *enc_tkt, krb5_db_entry *krbtgt);
+ krb5_enc_tkt_part *enc_tkt, krb5_db_entry *tgt,
+ krb5_keyblock *tgt_key);
/* do_as_req.c */
void
krb5_error_code
get_auth_indicators(krb5_context context, krb5_enc_tkt_part *enc_tkt,
- krb5_db_entry *local_tgt, krb5_data ***indicators_out);
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
+ krb5_data ***indicators_out);
krb5_error_code
handle_authdata (krb5_context context,
krb5_db_entry *server,
krb5_db_entry *header_server,
krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key,
krb5_keyblock *client_key,
krb5_keyblock *server_key,
krb5_keyblock *header_key,
krb5_error_code
kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state,
- krb5_kdc_req *req, krb5_db_entry *local_tgt);
+ krb5_kdc_req *req, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key);
krb5_boolean kdc_fast_search_cookie(struct kdc_request_state *state,
krb5_preauthtype pa_type, krb5_data *out);
krb5_error_code
kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
- krb5_db_entry *local_tgt,
+ krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
krb5_const_principal client_princ,
krb5_pa_data **cookie_out);