Skip to content

Commit

Permalink
Track first local TGT key in KDC code
Browse files Browse the repository at this point in the history
Decrypt the first local TGT key in get_local_tgt() and save it in the
AS and TGS processing functions.  (As we now sort key data by
descending kvno, this is guaranteed to be the most recent key.)  Pass
this key to the authdata and FAST cookie functions to simplify cookie
encryption and authdata signing.  Decryption and verification
functions must still sometimes decrypt earlier keys to process tickets
predating the last local TGT key rollover.
  • Loading branch information
greghudson committed Aug 27, 2019
1 parent e12e890 commit 570967e
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 165 deletions.
52 changes: 27 additions & 25 deletions src/kdc/cammac.c
Expand Up @@ -47,21 +47,22 @@ encode_kdcver_encpart(krb5_enc_tkt_part *enc_tkt, krb5_authdata **contents,
}

/*
* 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;

Expand All @@ -70,24 +71,16 @@ cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt,
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;

Expand Down Expand Up @@ -133,15 +126,19 @@ cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt,
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;

Expand All @@ -152,18 +149,23 @@ cammac_check_kdcver(krb5_context context, krb5_cammac *cammac,

/* 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;

/* Verify the checksum over the DER-encoded enc_tkt with the CAMMAC
* 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:
Expand Down
43 changes: 20 additions & 23 deletions src/kdc/do_as_req.c
Expand Up @@ -76,8 +76,8 @@

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
Expand Down Expand Up @@ -157,6 +157,7 @@ struct as_req_state {
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;
Expand Down Expand Up @@ -294,21 +295,12 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
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);
Expand Down Expand Up @@ -405,8 +397,9 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code 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);
Expand All @@ -419,6 +412,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
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)
Expand Down Expand Up @@ -667,7 +662,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,

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;
Expand Down Expand Up @@ -802,7 +797,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
}

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;
Expand All @@ -826,7 +821,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,

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)
{
Expand All @@ -848,7 +844,8 @@ prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request,
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;
}

Expand Down
11 changes: 7 additions & 4 deletions src/kdc/do_tgs_req.c
Expand Up @@ -115,7 +115,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
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;
Expand Down Expand Up @@ -144,6 +144,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
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
Expand Down Expand Up @@ -203,7 +204,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
}

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;
Expand Down Expand Up @@ -361,7 +362,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
* 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;
Expand Down Expand Up @@ -606,7 +607,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
}

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 */
Expand Down Expand Up @@ -798,6 +799,8 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
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)
Expand Down

0 comments on commit 570967e

Please sign in to comment.