aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2021-07-05 10:57:12 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-07-15 04:52:30 +0000
commit94ac641efabc9830bc91db1c793bf0ba42f1e46c (patch)
tree0e5878657135782f485f14748e4ad8714456f8eb
parent8cd877fc4d88e20bc3aaa4a4d53c35846bbcede5 (diff)
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 <metze@samba.org>
-rw-r--r--cmake/modules/FindKERBEROS.cmake2
-rw-r--r--cmakeconfig.h.in6
-rw-r--r--epan/dissectors/asn1/kerberos/packet-kerberos-template.c252
-rw-r--r--epan/dissectors/packet-kerberos.c264
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[] = {