From 94ac641efabc9830bc91db1c793bf0ba42f1e46c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 5 Jul 2021 10:57:12 +0200 Subject: [PATCH] packet-kerberos: implement PAC Ticket checksum verification We use some private functions from MIT kerberos: - krb5_free_enc_tkt_part() - decode_krb5_enc_tkt_part() - encode_krb5_enc_tkt_part() but we already do that for krb5int_c_mandatory_cksumtype(), which is newer than the above functions. We use all of them only under HAVE_KRB5_PAC_VERIFY, so we don't seem to need additional configure tests. Signed-off-by: Stefan Metzmacher --- cmake/modules/FindKERBEROS.cmake | 2 + cmakeconfig.h.in | 6 + .../asn1/kerberos/packet-kerberos-template.c | 252 +++++++++++++++++ epan/dissectors/packet-kerberos.c | 264 +++++++++++++++++- 4 files changed, 518 insertions(+), 6 deletions(-) diff --git a/cmake/modules/FindKERBEROS.cmake b/cmake/modules/FindKERBEROS.cmake index 322d72ae8b..38cd55a3ab 100644 --- a/cmake/modules/FindKERBEROS.cmake +++ b/cmake/modules/FindKERBEROS.cmake @@ -92,6 +92,8 @@ if(KERBEROS_FOUND) check_symbol_exists("krb5_pac_verify" "krb5.h" HAVE_KRB5_PAC_VERIFY) # see also HAVE_KRB5_C_FX_CF2_SIMPLE in cmakeconfig.h.in check_symbol_exists("krb5_c_fx_cf2_simple" "krb5.h" HAVE_KRB5_C_FX_CF2_SIMPLE) + check_function_exists(decode_krb5_enc_tkt_part HAVE_DECODE_KRB5_ENC_TKT_PART) + check_function_exists(encode_krb5_enc_tkt_part HAVE_ENCODE_KRB5_ENC_TKT_PART) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(NOT HAVE_HEIMDAL_KERBEROS) diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index ce448ed912..d8ec896027 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -91,6 +91,12 @@ /* Define to 1 if you have the `krb5_c_fx_cf2_simple' function. */ #cmakedefine HAVE_KRB5_C_FX_CF2_SIMPLE 1 +/* Define to 1 if you have the `decode_krb5_enc_tkt_part' function. */ +#cmakedefine HAVE_DECODE_KRB5_ENC_TKT_PART 1 + +/* Define to 1 if you have the `encode_krb5_enc_tkt_part' function. */ +#cmakedefine HAVE_ENCODE_KRB5_ENC_TKT_PART 1 + /* Define to 1 if you have the `inflatePrime' function. */ #cmakedefine HAVE_INFLATEPRIME 1 diff --git a/epan/dissectors/asn1/kerberos/packet-kerberos-template.c b/epan/dissectors/asn1/kerberos/packet-kerberos-template.c index e121730df0..397f558a92 100644 --- a/epan/dissectors/asn1/kerberos/packet-kerberos-template.c +++ b/epan/dissectors/asn1/kerberos/packet-kerberos-template.c @@ -126,6 +126,7 @@ typedef struct { #ifdef HAVE_KERBEROS enc_key_t *last_decryption_key; enc_key_t *last_added_key; + tvbuff_t *last_ticket_enc_part_tvb; #endif gint save_encryption_key_parent_hf_index; kerberos_key_save_fn save_encryption_key_fn; @@ -1792,6 +1793,12 @@ decrypt_krb5_krb_cfx_dce(proto_tree *tree, extern krb5_error_code krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *); +extern void krb5_free_enc_tkt_part(krb5_context, krb5_enc_tkt_part *); +extern krb5_error_code +decode_krb5_enc_tkt_part(const krb5_data *output, krb5_enc_tkt_part **rep); +extern krb5_error_code +encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code); + static int keytype_for_cksumtype(krb5_cksumtype checksum) { @@ -1829,6 +1836,8 @@ struct verify_krb5_pac_state { krb5_cksumtype kdc_checksum; guint kdc_count; enc_key_t *kdc_ek; + krb5_cksumtype ticket_checksum_type; + const krb5_data *ticket_checksum_data; }; static void @@ -1929,12 +1938,236 @@ verify_krb5_pac_try_kdc_key(gpointer __key _U_, gpointer value, gpointer userdat } } +#define __KRB5_PAC_TICKET_CHECKSUM 16 + +static void +verify_krb5_pac_ticket_checksum(proto_tree *tree _U_, + asn1_ctx_t *actx _U_, + tvbuff_t *pactvb _U_, + struct verify_krb5_pac_state *state _U_) +{ +#ifdef HAVE_DECODE_KRB5_ENC_TKT_PART + kerberos_private_data_t *private_data = kerberos_get_private_data(actx); + tvbuff_t *teptvb = private_data->last_ticket_enc_part_tvb; + guint teplength = 0; + const guint8 *tepbuffer = NULL; + krb5_data tepdata = { .length = 0, }; + krb5_enc_tkt_part *tep = NULL; + krb5_data *tmpdata = NULL; + krb5_error_code ret; + krb5_authdata **recoded_container = NULL; + gint ad_orig_idx = -1; + krb5_authdata *ad_orig_ptr = NULL; + gint l0idx = 0; + krb5_keyblock kdc_key = { .magic = KV5M_KEYBLOCK, }; + size_t checksum_length = 0; + krb5_checksum checksum = { .checksum_type = 0, }; + krb5_boolean valid = FALSE; + + if (state->kdc_ek == NULL) { + int keytype = keytype_for_cksumtype(state->ticket_checksum_type); + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + keytype, + "Missing KDC (for ticket)", + "kdc_checksum_key", + 0, + 0); + return; + } + + if (teptvb == NULL) { + return; + } + + teplength = tvb_captured_length(teptvb); + /* make sure we have all the data we need */ + if (teplength < tvb_reported_length(teptvb)) { + return; + } + + tepbuffer = tvb_get_ptr(teptvb, 0, teplength); + if (tepbuffer == NULL) { + return; + } + + kdc_key.magic = KV5M_KEYBLOCK; + kdc_key.enctype = state->kdc_ek->keytype; + kdc_key.length = state->kdc_ek->keylength; + kdc_key.contents = (guint8 *)state->kdc_ek->keyvalue; + + checksum.checksum_type = state->ticket_checksum_type; + checksum.length = state->ticket_checksum_data->length; + checksum.contents = (guint8 *)state->ticket_checksum_data->data; + if (checksum.length >= 4) { + checksum.length -= 4; + checksum.contents += 4; + } + + ret = krb5_c_checksum_length(krb5_ctx, + checksum.checksum_type, + &checksum_length); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_c_checksum_length failed for Ticket Signature", + "kdc_checksum_key", + 1, + 0); + return; + } + checksum.length = MIN(checksum.length, (unsigned int)checksum_length); + + tepdata.data = (void *)(uintptr_t)tepbuffer; + tepdata.length = teplength; + + ret = decode_krb5_enc_tkt_part(&tepdata, &tep); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "decode_krb5_enc_tkt_part failed", + "kdc_checksum_key", + 1, + 0); + return; + } + + for (l0idx = 0; tep->authorization_data[l0idx]; l0idx++) { + krb5_authdata *adl0 = tep->authorization_data[l0idx]; + krb5_authdata **decoded_container = NULL; + krb5_authdata *ad_pac = NULL; + gint l1idx = 0; + + if (adl0->ad_type != KRB5_AUTHDATA_IF_RELEVANT) { + continue; + } + + ret = krb5_decode_authdata_container(krb5_ctx, + KRB5_AUTHDATA_IF_RELEVANT, + adl0, + &decoded_container); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_decode_authdata_container failed", + "kdc_checksum_key", + 1, + 0); + krb5_free_enc_tkt_part(krb5_ctx, tep); + return; + } + + for (l1idx = 0; decoded_container[l1idx]; l1idx++) { + krb5_authdata *adl1 = decoded_container[l1idx]; + + if (adl1->ad_type != KRB5_AUTHDATA_WIN2K_PAC) { + continue; + } + + ad_pac = adl1; + break; + } + + if (ad_pac == NULL) { + krb5_free_authdata(krb5_ctx, decoded_container); + continue; + } + + ad_pac->length = 1; + ad_pac->contents[0] = '\0'; + + ret = krb5_encode_authdata_container(krb5_ctx, + KRB5_AUTHDATA_IF_RELEVANT, + decoded_container, + &recoded_container); + krb5_free_authdata(krb5_ctx, decoded_container); + decoded_container = NULL; + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_encode_authdata_container failed", + "kdc_checksum_key", + 1, + 0); + krb5_free_enc_tkt_part(krb5_ctx, tep); + return; + } + + ad_orig_idx = l0idx; + ad_orig_ptr = adl0; + tep->authorization_data[l0idx] = recoded_container[0]; + break; + } + + ret = encode_krb5_enc_tkt_part(tep, &tmpdata); + if (ad_orig_ptr != NULL) { + tep->authorization_data[ad_orig_idx] = ad_orig_ptr; + } + krb5_free_enc_tkt_part(krb5_ctx, tep); + tep = NULL; + if (recoded_container != NULL) { + krb5_free_authdata(krb5_ctx, recoded_container); + recoded_container = NULL; + } + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "encode_krb5_enc_tkt_part failed", + "kdc_checksum_key", + 1, + 0); + return; + } + + ret = krb5_c_verify_checksum(krb5_ctx, &kdc_key, + KRB5_KEYUSAGE_APP_DATA_CKSUM, + tmpdata, &checksum, &valid); + krb5_free_data(krb5_ctx, tmpdata); + tmpdata = NULL; + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_c_verify_checksum failed for Ticket Signature", + "kdc_checksum_key", + 1, + 1); + return; + } + + if (valid == FALSE) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "Invalid Ticket", + "kdc_checksum_key", + 1, + 1); + return; + } + + used_signing_key(tree, actx->pinfo, private_data, + state->kdc_ek, pactvb, + state->ticket_checksum_type, + "Verified Ticket", + "kdc_checksum_key", + 1, + 1); +#endif /* HAVE_DECODE_KRB5_ENC_TKT_PART */ +} + static void verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) { kerberos_private_data_t *private_data = kerberos_get_private_data(actx); krb5_error_code ret; krb5_data checksum_data = {0,0,NULL}; + krb5_data ticket_checksum_data = {0,0,NULL}; int length = tvb_captured_length(pactvb); const guint8 *pacbuffer = NULL; struct verify_krb5_pac_state state = { @@ -1974,6 +2207,13 @@ verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) state.kdc_checksum = pletoh32(checksum_data.data); krb5_free_data_contents(krb5_ctx, &checksum_data); }; + ret = krb5_pac_get_buffer(krb5_ctx, state.pac, + __KRB5_PAC_TICKET_CHECKSUM, + &ticket_checksum_data); + if (ret == 0) { + state.ticket_checksum_data = &ticket_checksum_data; + state.ticket_checksum_type = pletoh32(ticket_checksum_data.data); + }; read_keytab_file_from_preferences(); @@ -2016,6 +2256,14 @@ verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) state.kdc_count); } + if (state.ticket_checksum_type != 0) { + verify_krb5_pac_ticket_checksum(tree, actx, pactvb, &state); + } + + if (state.ticket_checksum_data != NULL) { + krb5_free_data_contents(krb5_ctx, &ticket_checksum_data); + } + krb5_pac_free(krb5_ctx, state.pac); } #endif /* HAVE_KRB5_PAC_VERIFY */ @@ -2829,13 +3077,17 @@ dissect_krb5_decrypt_ticket_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offse plaintext=decrypt_krb5_data_asn1(tree, actx, 2, next_tvb, &length); if(plaintext){ + kerberos_private_data_t *private_data = kerberos_get_private_data(actx); + tvbuff_t *last_ticket_enc_part_tvb = private_data->last_ticket_enc_part_tvb; tvbuff_t *child_tvb; child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length); /* Add the decrypted data to the data source list. */ add_new_data_source(actx->pinfo, child_tvb, "Krb5 Ticket"); + private_data->last_ticket_enc_part_tvb = child_tvb; offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1); + private_data->last_ticket_enc_part_tvb = last_ticket_enc_part_tvb; } return offset; } diff --git a/epan/dissectors/packet-kerberos.c b/epan/dissectors/packet-kerberos.c index 6f9592e97b..c6f081165b 100644 --- a/epan/dissectors/packet-kerberos.c +++ b/epan/dissectors/packet-kerberos.c @@ -134,6 +134,7 @@ typedef struct { #ifdef HAVE_KERBEROS enc_key_t *last_decryption_key; enc_key_t *last_added_key; + tvbuff_t *last_ticket_enc_part_tvb; #endif gint save_encryption_key_parent_hf_index; kerberos_key_save_fn save_encryption_key_fn; @@ -533,7 +534,7 @@ static int hf_kerberos_PAC_OPTIONS_FLAGS_forward_to_full_dc = -1; static int hf_kerberos_PAC_OPTIONS_FLAGS_resource_based_constrained_delegation = -1; /*--- End of included file: packet-kerberos-hf.c ---*/ -#line 295 "./asn1/kerberos/packet-kerberos-template.c" +#line 296 "./asn1/kerberos/packet-kerberos-template.c" /* Initialize the subtree pointers */ static gint ett_kerberos = -1; @@ -650,7 +651,7 @@ static gint ett_kerberos_SPAKEResponse = -1; static gint ett_kerberos_PA_SPAKE = -1; /*--- End of included file: packet-kerberos-ett.c ---*/ -#line 322 "./asn1/kerberos/packet-kerberos-template.c" +#line 323 "./asn1/kerberos/packet-kerberos-template.c" static expert_field ei_kerberos_missing_keytype = EI_INIT; static expert_field ei_kerberos_decrypted_keytype = EI_INIT; @@ -781,7 +782,7 @@ typedef enum _KERBEROS_KRBFASTARMORTYPES_enum { } KERBEROS_KRBFASTARMORTYPES_enum; /*--- End of included file: packet-kerberos-val.h ---*/ -#line 336 "./asn1/kerberos/packet-kerberos-template.c" +#line 337 "./asn1/kerberos/packet-kerberos-template.c" static void call_kerberos_callbacks(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int tag, kerberos_callbacks *cb) @@ -2241,6 +2242,12 @@ decrypt_krb5_krb_cfx_dce(proto_tree *tree, extern krb5_error_code krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *); +extern void krb5_free_enc_tkt_part(krb5_context, krb5_enc_tkt_part *); +extern krb5_error_code +decode_krb5_enc_tkt_part(const krb5_data *output, krb5_enc_tkt_part **rep); +extern krb5_error_code +encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code); + static int keytype_for_cksumtype(krb5_cksumtype checksum) { @@ -2278,6 +2285,8 @@ struct verify_krb5_pac_state { krb5_cksumtype kdc_checksum; guint kdc_count; enc_key_t *kdc_ek; + krb5_cksumtype ticket_checksum_type; + const krb5_data *ticket_checksum_data; }; static void @@ -2378,12 +2387,236 @@ verify_krb5_pac_try_kdc_key(gpointer __key _U_, gpointer value, gpointer userdat } } +#define __KRB5_PAC_TICKET_CHECKSUM 16 + +static void +verify_krb5_pac_ticket_checksum(proto_tree *tree _U_, + asn1_ctx_t *actx _U_, + tvbuff_t *pactvb _U_, + struct verify_krb5_pac_state *state _U_) +{ +#ifdef HAVE_DECODE_KRB5_ENC_TKT_PART + kerberos_private_data_t *private_data = kerberos_get_private_data(actx); + tvbuff_t *teptvb = private_data->last_ticket_enc_part_tvb; + guint teplength = 0; + const guint8 *tepbuffer = NULL; + krb5_data tepdata = { .length = 0, }; + krb5_enc_tkt_part *tep = NULL; + krb5_data *tmpdata = NULL; + krb5_error_code ret; + krb5_authdata **recoded_container = NULL; + gint ad_orig_idx = -1; + krb5_authdata *ad_orig_ptr = NULL; + gint l0idx = 0; + krb5_keyblock kdc_key = { .magic = KV5M_KEYBLOCK, }; + size_t checksum_length = 0; + krb5_checksum checksum = { .checksum_type = 0, }; + krb5_boolean valid = FALSE; + + if (state->kdc_ek == NULL) { + int keytype = keytype_for_cksumtype(state->ticket_checksum_type); + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + keytype, + "Missing KDC (for ticket)", + "kdc_checksum_key", + 0, + 0); + return; + } + + if (teptvb == NULL) { + return; + } + + teplength = tvb_captured_length(teptvb); + /* make sure we have all the data we need */ + if (teplength < tvb_reported_length(teptvb)) { + return; + } + + tepbuffer = tvb_get_ptr(teptvb, 0, teplength); + if (tepbuffer == NULL) { + return; + } + + kdc_key.magic = KV5M_KEYBLOCK; + kdc_key.enctype = state->kdc_ek->keytype; + kdc_key.length = state->kdc_ek->keylength; + kdc_key.contents = (guint8 *)state->kdc_ek->keyvalue; + + checksum.checksum_type = state->ticket_checksum_type; + checksum.length = state->ticket_checksum_data->length; + checksum.contents = (guint8 *)state->ticket_checksum_data->data; + if (checksum.length >= 4) { + checksum.length -= 4; + checksum.contents += 4; + } + + ret = krb5_c_checksum_length(krb5_ctx, + checksum.checksum_type, + &checksum_length); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_c_checksum_length failed for Ticket Signature", + "kdc_checksum_key", + 1, + 0); + return; + } + checksum.length = MIN(checksum.length, (unsigned int)checksum_length); + + tepdata.data = (void *)(uintptr_t)tepbuffer; + tepdata.length = teplength; + + ret = decode_krb5_enc_tkt_part(&tepdata, &tep); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "decode_krb5_enc_tkt_part failed", + "kdc_checksum_key", + 1, + 0); + return; + } + + for (l0idx = 0; tep->authorization_data[l0idx]; l0idx++) { + krb5_authdata *adl0 = tep->authorization_data[l0idx]; + krb5_authdata **decoded_container = NULL; + krb5_authdata *ad_pac = NULL; + gint l1idx = 0; + + if (adl0->ad_type != KRB5_AUTHDATA_IF_RELEVANT) { + continue; + } + + ret = krb5_decode_authdata_container(krb5_ctx, + KRB5_AUTHDATA_IF_RELEVANT, + adl0, + &decoded_container); + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_decode_authdata_container failed", + "kdc_checksum_key", + 1, + 0); + krb5_free_enc_tkt_part(krb5_ctx, tep); + return; + } + + for (l1idx = 0; decoded_container[l1idx]; l1idx++) { + krb5_authdata *adl1 = decoded_container[l1idx]; + + if (adl1->ad_type != KRB5_AUTHDATA_WIN2K_PAC) { + continue; + } + + ad_pac = adl1; + break; + } + + if (ad_pac == NULL) { + krb5_free_authdata(krb5_ctx, decoded_container); + continue; + } + + ad_pac->length = 1; + ad_pac->contents[0] = '\0'; + + ret = krb5_encode_authdata_container(krb5_ctx, + KRB5_AUTHDATA_IF_RELEVANT, + decoded_container, + &recoded_container); + krb5_free_authdata(krb5_ctx, decoded_container); + decoded_container = NULL; + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_encode_authdata_container failed", + "kdc_checksum_key", + 1, + 0); + krb5_free_enc_tkt_part(krb5_ctx, tep); + return; + } + + ad_orig_idx = l0idx; + ad_orig_ptr = adl0; + tep->authorization_data[l0idx] = recoded_container[0]; + break; + } + + ret = encode_krb5_enc_tkt_part(tep, &tmpdata); + if (ad_orig_ptr != NULL) { + tep->authorization_data[ad_orig_idx] = ad_orig_ptr; + } + krb5_free_enc_tkt_part(krb5_ctx, tep); + tep = NULL; + if (recoded_container != NULL) { + krb5_free_authdata(krb5_ctx, recoded_container); + recoded_container = NULL; + } + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "encode_krb5_enc_tkt_part failed", + "kdc_checksum_key", + 1, + 0); + return; + } + + ret = krb5_c_verify_checksum(krb5_ctx, &kdc_key, + KRB5_KEYUSAGE_APP_DATA_CKSUM, + tmpdata, &checksum, &valid); + krb5_free_data(krb5_ctx, tmpdata); + tmpdata = NULL; + if (ret != 0) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "krb5_c_verify_checksum failed for Ticket Signature", + "kdc_checksum_key", + 1, + 1); + return; + } + + if (valid == FALSE) { + missing_signing_key(tree, actx->pinfo, private_data, + pactvb, state->ticket_checksum_type, + state->kdc_ek->keytype, + "Invalid Ticket", + "kdc_checksum_key", + 1, + 1); + return; + } + + used_signing_key(tree, actx->pinfo, private_data, + state->kdc_ek, pactvb, + state->ticket_checksum_type, + "Verified Ticket", + "kdc_checksum_key", + 1, + 1); +#endif /* HAVE_DECODE_KRB5_ENC_TKT_PART */ +} + static void verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) { kerberos_private_data_t *private_data = kerberos_get_private_data(actx); krb5_error_code ret; krb5_data checksum_data = {0,0,NULL}; + krb5_data ticket_checksum_data = {0,0,NULL}; int length = tvb_captured_length(pactvb); const guint8 *pacbuffer = NULL; struct verify_krb5_pac_state state = { @@ -2423,6 +2656,13 @@ verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) state.kdc_checksum = pletoh32(checksum_data.data); krb5_free_data_contents(krb5_ctx, &checksum_data); }; + ret = krb5_pac_get_buffer(krb5_ctx, state.pac, + __KRB5_PAC_TICKET_CHECKSUM, + &ticket_checksum_data); + if (ret == 0) { + state.ticket_checksum_data = &ticket_checksum_data; + state.ticket_checksum_type = pletoh32(ticket_checksum_data.data); + }; read_keytab_file_from_preferences(); @@ -2465,6 +2705,14 @@ verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb) state.kdc_count); } + if (state.ticket_checksum_type != 0) { + verify_krb5_pac_ticket_checksum(tree, actx, pactvb, &state); + } + + if (state.ticket_checksum_data != NULL) { + krb5_free_data_contents(krb5_ctx, &ticket_checksum_data); + } + krb5_pac_free(krb5_ctx, state.pac); } #endif /* HAVE_KRB5_PAC_VERIFY */ @@ -3278,13 +3526,17 @@ dissect_krb5_decrypt_ticket_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offse plaintext=decrypt_krb5_data_asn1(tree, actx, 2, next_tvb, &length); if(plaintext){ + kerberos_private_data_t *private_data = kerberos_get_private_data(actx); + tvbuff_t *last_ticket_enc_part_tvb = private_data->last_ticket_enc_part_tvb; tvbuff_t *child_tvb; child_tvb = tvb_new_child_real_data(tvb, plaintext, length, length); /* Add the decrypted data to the data source list. */ add_new_data_source(actx->pinfo, child_tvb, "Krb5 Ticket"); + private_data->last_ticket_enc_part_tvb = child_tvb; offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1); + private_data->last_ticket_enc_part_tvb = last_ticket_enc_part_tvb; } return offset; } @@ -7429,7 +7681,7 @@ dissect_kerberos_PA_SPAKE(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offs /*--- End of included file: packet-kerberos-fn.c ---*/ -#line 3902 "./asn1/kerberos/packet-kerberos-template.c" +#line 4154 "./asn1/kerberos/packet-kerberos-template.c" #ifdef HAVE_KERBEROS static const ber_sequence_t PA_ENC_TS_ENC_sequence[] = { @@ -9239,7 +9491,7 @@ void proto_register_kerberos(void) { NULL, HFILL }}, /*--- End of included file: packet-kerberos-hfarr.c ---*/ -#line 4795 "./asn1/kerberos/packet-kerberos-template.c" +#line 5047 "./asn1/kerberos/packet-kerberos-template.c" }; /* List of subtrees */ @@ -9358,7 +9610,7 @@ void proto_register_kerberos(void) { &ett_kerberos_PA_SPAKE, /*--- End of included file: packet-kerberos-ettarr.c ---*/ -#line 4824 "./asn1/kerberos/packet-kerberos-template.c" +#line 5076 "./asn1/kerberos/packet-kerberos-template.c" }; static ei_register_info ei[] = {