no krb5_cksumtype_to_string
[metze/wireshark/wip.git] / epan / dissectors / asn1 / kerberos / packet-kerberos-template.c
index 7ca1c98496633eb006564340dc1b72a8b73e925d..87fbcbec236738ce3204c8c9c1d8615ddc8fd6d2 100644 (file)
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 /*
 
 #include <config.h>
 
+//TODO
+#define HAVE_KRB5_CRYPTO_FX_CF2 1
+#define HAVE_KRB5_C_FX_CF2_SIMPLE 1
+
 #include <stdio.h>
 
 #include <epan/packet.h>
 #include <epan/asn1.h>
 #include <epan/expert.h>
 #include <epan/prefs.h>
+#include <epan/proto_data.h>
 #include <wsutil/wsgcrypt.h>
 #include <wsutil/file_util.h>
 #include <wsutil/str_util.h>
+#include <wsutil/pint.h>
 #include "packet-kerberos.h"
 #include "packet-netbios.h"
 #include "packet-tcp.h"
 
 #include "packet-gssapi.h"
 #include "packet-smb-common.h"
+#include "packet-x509af.h"
 
+#define KEY_USAGE_FAST_REQ_CHKSUM       50
+#define KEY_USAGE_FAST_ENC              51
+#define KEY_USAGE_FAST_REP              52
+#define KEY_USAGE_FAST_FINISHED         53
+#define KEY_USAGE_ENC_CHALLENGE_CLIENT  54
+#define KEY_USAGE_ENC_CHALLENGE_KDC     55
 
 void proto_register_kerberos(void);
 void proto_reg_handoff_kerberos(void);
@@ -98,30 +99,56 @@ typedef struct kerberos_key {
 } kerberos_key_t;
 
 typedef struct {
-       gboolean is_request;
+       guint32 msg_type;
+       gboolean kdc_response_initialized;
+       gboolean kdc_response;
+       guint32 errorcode;
+       gboolean try_nt_status;
        guint32 etype;
        guint32 padata_type;
+       guint32 is_enc_padata;
        guint32 enctype;
        kerberos_key_t key;
        guint32 ad_type;
        guint32 addr_type;
        guint32 checksum_type;
+       const enc_key_t *last_decryption_key;
+       gboolean is_win2k_pkinit;
+       guint32 fast_type;
+       gboolean fast_armor_request;
+       gboolean fast_armor_within_enc_ticket_part;
+       const enc_key_t *fast_armor_ticket_sessionkey;
+       gboolean fast_armor_within_authenticator;
+       const enc_key_t *fast_armor_remote_subkey;
+       const enc_key_t *fast_armor_key;
+       gboolean fast_strengthen_key_needed;
+       const enc_key_t *fast_strengthen_key;
 } kerberos_private_data_t;
 
 static dissector_handle_t kerberos_handle_udp;
 
 /* Forward declarations */
 static int dissect_kerberos_Applications(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_AuthorizationData(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_PA_ENC_TIMESTAMP(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
-static int dissect_kerberos_KERB_PA_PAC_REQUEST(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_ENC_TS_ENC(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_PAC_REQUEST(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_PA_S4U2Self(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_S4U_X509_USER(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_ETYPE_INFO(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_ETYPE_INFO2(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_AD_IF_RELEVANT(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
-static int dissect_kerberos_PA_AUTHENTICATION_SET(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_AUTHENTICATION_SET_ELEM(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_PA_FX_FAST_REQUEST(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
-static int dissect_kerberos_EncryptedChallenge(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 static int dissect_kerberos_PA_FX_FAST_REPLY(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_KrbFastReq(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_KrbFastResponse(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_EncryptedChallenge(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_SUPPORTED_ENCTYPES(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_PA_PAC_OPTIONS(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_KERB_AD_RESTRICTION_ENTRY(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_AD_AP_OPTIONS(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
+static int dissect_kerberos_Checksum(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
 
 /* Desegment Kerberos over TCP messages */
 static gboolean krb_desegment = TRUE;
@@ -162,7 +189,10 @@ static gint hf_krb_pac_clientid = -1;
 static gint hf_krb_pac_namelen = -1;
 static gint hf_krb_pac_clientname = -1;
 static gint hf_krb_pac_logon_info = -1;
-static gint hf_krb_pac_credential_type = -1;
+static gint hf_krb_pac_credential_data = -1;
+static gint hf_krb_pac_credential_info = -1;
+static gint hf_krb_pac_credential_info_version = -1;
+static gint hf_krb_pac_credential_info_etype = -1;
 static gint hf_krb_pac_s4u_delegation_info = -1;
 static gint hf_krb_pac_upn_dns_info = -1;
 static gint hf_krb_pac_upn_flags = -1;
@@ -175,6 +205,21 @@ static gint hf_krb_pac_upn_dns_name = -1;
 static gint hf_krb_pac_server_checksum = -1;
 static gint hf_krb_pac_privsvr_checksum = -1;
 static gint hf_krb_pac_client_info_type = -1;
+static gint hf_krb_pac_client_claims_info = -1;
+static gint hf_krb_pac_device_info = -1;
+static gint hf_krb_pac_device_claims_info = -1;
+static gint hf_krb_pa_supported_enctypes = -1;
+static gint hf_krb_pa_supported_enctypes_des_cbc_crc = -1;
+static gint hf_krb_pa_supported_enctypes_des_cbc_md5 = -1;
+static gint hf_krb_pa_supported_enctypes_rc4_hmac = -1;
+static gint hf_krb_pa_supported_enctypes_aes128_cts_hmac_sha1_96 = -1;
+static gint hf_krb_pa_supported_enctypes_aes256_cts_hmac_sha1_96 = -1;
+static gint hf_krb_pa_supported_enctypes_fast_supported = -1;
+static gint hf_krb_pa_supported_enctypes_compound_identity_supported = -1;
+static gint hf_krb_pa_supported_enctypes_claims_supported = -1;
+static gint hf_krb_pa_supported_enctypes_resource_sid_compression_disabled = -1;
+static gint hf_krb_ad_ap_options = -1;
+static gint hf_krb_ad_ap_options_cbt = -1;
 #include "packet-kerberos-hf.c"
 
 /* Initialize the subtree pointers */
@@ -184,11 +229,14 @@ static gint ett_krb_pac = -1;
 static gint ett_krb_pac_drep = -1;
 static gint ett_krb_pac_midl_blob = -1;
 static gint ett_krb_pac_logon_info = -1;
+static gint ett_krb_pac_credential_info = -1;
 static gint ett_krb_pac_s4u_delegation_info = -1;
 static gint ett_krb_pac_upn_dns_info = -1;
 static gint ett_krb_pac_server_checksum = -1;
 static gint ett_krb_pac_privsvr_checksum = -1;
 static gint ett_krb_pac_client_info_type = -1;
+static gint ett_krb_pa_supported_enctypes = -1;
+static gint ett_krb_ad_ap_options = -1;
 #include "packet-kerberos-ett.c"
 
 static expert_field ei_kerberos_decrypted_keytype = EI_INIT;
@@ -198,7 +246,6 @@ static expert_field ei_krb_gssapi_dlglen = EI_INIT;
 static dissector_handle_t krb4_handle=NULL;
 
 /* Global variables */
-static guint32 krb5_errorcode;
 static guint32 gbl_keytype;
 static gboolean gbl_do_col_info;
 
@@ -221,15 +268,34 @@ call_kerberos_callbacks(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int
        return;
 }
 
+static kerberos_private_data_t*
+kerberos_get_private_data_p(packet_info *pinfo)
+{
+       void *p = p_get_proto_data(pinfo->pool, pinfo, proto_kerberos, 0);
+       if (p == NULL) {
+               p = wmem_new0(pinfo->pool, kerberos_private_data_t);
+               p_add_proto_data(pinfo->pool, pinfo, proto_kerberos, 0, p);
+       }
+       return (kerberos_private_data_t *)(p);
+}
+
 static kerberos_private_data_t*
 kerberos_get_private_data(asn1_ctx_t *actx)
 {
-       if (!actx->private_data) {
-               actx->private_data = wmem_new0(wmem_packet_scope(), kerberos_private_data_t);
+       if (actx->private_data == NULL) {
+               actx->private_data = kerberos_get_private_data_p(actx->pinfo);
        }
        return (kerberos_private_data_t *)(actx->private_data);
 }
 
+gboolean
+kerberos_is_win2k_pkinit(asn1_ctx_t *actx)
+{
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+
+       return private_data->is_win2k_pkinit;
+}
+
 #ifdef HAVE_KERBEROS
 
 /* Decrypt Kerberos blobs */
@@ -276,7 +342,7 @@ add_encryption_key(packet_info *pinfo, int keytype, int keylength, const char *k
 {
        enc_key_t *new_key;
 
-       if(pinfo->fd->flags.visited){
+       if(pinfo->fd->visited){
                return;
        }
 
@@ -290,12 +356,112 @@ add_encryption_key(packet_info *pinfo, int keytype, int keylength, const char *k
        /*XXX this needs to be freed later */
        new_key->keyvalue=(char *)g_memdup(keyvalue, keylength);
 }
+
+static void used_encryption_key(proto_tree *tree, packet_info *pinfo,
+                               enc_key_t *ek, int usage, tvbuff_t *cryptotvb)
+{
+       kerberos_private_data_t *private_data = kerberos_get_private_data_p(pinfo);
+
+       proto_tree_add_expert_format(tree, pinfo, &ei_kerberos_decrypted_keytype,
+                                    cryptotvb, 0, 0,
+                                    "Decrypted keytype %d usage %d in frame %u "
+                                    "using %s (%02x%02x%02x%02x...)",
+                                    ek->keytype, pinfo->fd->num, usage, ek->key_origin,
+                                    ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF,
+                                    ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
+
+       private_data->last_decryption_key = ek;
+}
+
+static void used_signing_key(proto_tree *tree, packet_info *pinfo,
+                            enc_key_t *ek, tvbuff_t *tvb,
+                            krb5_cksumtype checksum,
+                            const char *reason)
+{
+       proto_tree_add_expert_format(tree, pinfo, &ei_kerberos_decrypted_keytype,
+                                    tvb, 0, 0,
+                                    "%s checksum %d keytype %d in frame %u "
+                                    "using %s (%02x%02x%02x%02x...)",
+                                    reason, checksum, ek->keytype, pinfo->fd->num, ek->key_origin,
+                                    ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF,
+                                    ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
+}
+
+static void
+krb5_fast_key(packet_info *pinfo,
+             const enc_key_t *ek1, const char *p1,
+             const enc_key_t *ek2, const char *p2,
+             const char *origin);
+
+static void
+krb5_fast_armor_key(packet_info *pinfo,
+                   const enc_key_t *remote_subkey,
+                   const enc_key_t *ticket_sessionkey)
+{
+       kerberos_private_data_t *private_data = kerberos_get_private_data_p(pinfo);
+
+       krb5_fast_key(pinfo,
+                     remote_subkey,
+                     "subkeyarmor",
+                     ticket_sessionkey,
+                     "ticketarmor",
+                     "armorkey");
+
+       private_data->fast_armor_key = enc_key_list;
+}
+
 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
 
 #if defined(HAVE_MIT_KERBEROS)
 
 static krb5_context krb5_ctx;
 
+static void
+krb5_fast_key(packet_info *pinfo,
+             const enc_key_t *ek1, const char *p1,
+             const enc_key_t *ek2, const char *p2,
+             const char *origin)
+{
+#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
+       krb5_error_code ret;
+       krb5_keyblock k1;
+       krb5_keyblock k2;
+       krb5_keyblock *k = NULL;
+
+       if (!krb_decrypt) {
+               return;
+       }
+
+       if (ek1 == NULL) {
+               return;
+       }
+
+       if (ek2 == NULL) {
+               return;
+       }
+
+       k1.magic = KV5M_KEYBLOCK;
+       k1.enctype = ek1->keytype;
+       k1.length = ek1->keylength;
+       k1.contents = (guint8 *)ek1->keyvalue;
+
+       k2.magic = KV5M_KEYBLOCK;
+       k2.enctype = ek2->keytype;
+       k2.length = ek2->keylength;
+       k2.contents = (guint8 *)ek2->keyvalue;
+
+       ret = krb5_c_fx_cf2_simple(krb5_ctx, &k1, p1, &k2, p2, &k);
+       if (ret != 0) {
+               return;
+       }
+
+       add_encryption_key(pinfo, k->enctype, k->length,
+                          (const char *)k->contents, origin);
+
+       krb5_free_keyblock(krb5_ctx, k);
+#endif
+}
+
 USES_APPLE_DEPRECATED_API
 void
 read_keytab_file(const char *filename)
@@ -304,7 +470,6 @@ read_keytab_file(const char *filename)
        krb5_error_code ret;
        krb5_keytab_entry key;
        krb5_kt_cursor cursor;
-       enc_key_t *new_key;
        static gboolean first_time=TRUE;
 
        if (filename == NULL || filename[0] == 0) {
@@ -334,14 +499,16 @@ read_keytab_file(const char *filename)
        }
 
        do{
-               new_key=(enc_key_t *)g_malloc(sizeof(enc_key_t));
-               new_key->fd_num = -1;
-               new_key->next=enc_key_list;
                ret = krb5_kt_next_entry(krb5_ctx, keytab, &key, &cursor);
                if(ret==0){
+                       enc_key_t *new_key;
                        int i;
                        char *pos;
 
+                       new_key = g_new(enc_key_t, 1);
+                       new_key->fd_num = -1;
+                       new_key->next = enc_key_list;
+
                        /* generate origin string, describing where this key came from */
                        pos=new_key->key_origin;
                        pos+=MIN(KRB_MAX_ORIG_LEN,
@@ -357,12 +524,21 @@ read_keytab_file(const char *filename)
                        new_key->keylength=key.key.length;
                        new_key->keyvalue=(char *)g_memdup(key.key.contents, key.key.length);
                        enc_key_list=new_key;
+                       ret = krb5_free_keytab_entry_contents(krb5_ctx, &key);
+                       if (ret) {
+                               fprintf(stderr, "KERBEROS ERROR: Could not release the entry: %d", ret);
+                               ret = 0; /* try to continue with the next entry */
+                       }
                }
        }while(ret==0);
 
        ret = krb5_kt_end_seq_get(krb5_ctx, keytab, &cursor);
        if(ret){
-               krb5_kt_close(krb5_ctx, keytab);
+               fprintf(stderr, "KERBEROS ERROR: Could not release the keytab cursor: %d", ret);
+       }
+       ret = krb5_kt_close(krb5_ctx, keytab);
+       if(ret){
+               fprintf(stderr, "KERBEROS ERROR: Could not close the key table handle: %d", ret);
        }
 }
 
@@ -374,6 +550,11 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
                                        int keytype,
                                        int *datalen)
 {
+       kerberos_private_data_t *private_data = kerberos_get_private_data_p(pinfo);
+#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
+       const enc_key_t *ak = private_data->fast_armor_key;
+       const enc_key_t *sk = private_data->fast_strengthen_key;
+#endif
        krb5_error_code ret;
        enc_key_t *ek;
        krb5_data data = {0,0,NULL};
@@ -407,6 +588,109 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
                input.ciphertext.length = length;
                input.ciphertext.data = (guint8 *)cryptotext;
 
+#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
+               if (ak == ek) {
+                       continue;
+               }
+
+               if (ak != NULL && ak != ek && ak->keytype == ek->keytype) {
+                       krb5_keyblock k1;
+                       krb5_keyblock k2;
+                       krb5_keyblock *k = NULL;
+                       const char *p1 = NULL;
+
+                       k1.magic = KV5M_KEYBLOCK;
+                       k1.enctype = ak->keytype;
+                       k1.length = ak->keylength;
+                       k1.contents = (guint8 *)ak->keyvalue;
+
+                       k2.magic = KV5M_KEYBLOCK;
+                       k2.enctype = ek->keytype;
+                       k2.length = ek->keylength;
+                       k2.contents = (guint8 *)ek->keyvalue;
+
+                       if (private_data->kdc_response) {
+                               p1 = "kdcchallengearmor";
+                       } else {
+                               p1 = "clientchallengearmor";
+                       }
+
+                       ret = krb5_c_fx_cf2_simple(krb5_ctx,
+                                                  &k1, p1,
+                                                  &k2, "challengelongterm",
+                                                  &k);
+                       if (ret != 0) {
+                               continue;
+                       }
+
+                       ret = krb5_c_decrypt(krb5_ctx, k, usage, 0, &input, &data);
+                       if(ret == 0) {
+                               char *user_data;
+
+                               add_encryption_key(pinfo, k->enctype, k->length,
+                                                  (const char *)k->contents,
+                                                  p1);
+                               krb5_free_keyblock(krb5_ctx, k);
+                               ek = enc_key_list;
+                               used_encryption_key(tree, pinfo, ek, usage, cryptotvb);
+
+                               /* return a private g_malloced blob to the caller */
+                               user_data=data.data;
+                               if (datalen) {
+                                       *datalen = data.length;
+                               }
+                               return user_data;
+                       }
+
+                       krb5_free_keyblock(krb5_ctx, k);
+               }
+
+               if (sk != NULL && sk != ek && sk->keytype == ek->keytype) {
+                       krb5_keyblock k1;
+                       krb5_keyblock k2;
+                       krb5_keyblock *k = NULL;
+
+                       k1.magic = KV5M_KEYBLOCK;
+                       k1.enctype = sk->keytype;
+                       k1.length = sk->keylength;
+                       k1.contents = (guint8 *)sk->keyvalue;
+
+                       k2.magic = KV5M_KEYBLOCK;
+                       k2.enctype = ek->keytype;
+                       k2.length = ek->keylength;
+                       k2.contents = (guint8 *)ek->keyvalue;
+
+                       ret = krb5_c_fx_cf2_simple(krb5_ctx,
+                                                  &k1, "strengthenkey",
+                                                  &k2, "replykey",
+                                                  &k);
+                       if (ret != 0) {
+                               continue;
+                       }
+
+                       ret = krb5_c_decrypt(krb5_ctx, k, usage, 0, &input, &data);
+                       if(ret == 0) {
+                               char *user_data;
+
+                               add_encryption_key(pinfo, k->enctype, k->length,
+                                                  (const char *)k->contents,
+                                                  "strengthenkey");
+                               krb5_free_keyblock(krb5_ctx, k);
+                               ek = enc_key_list;
+                               used_encryption_key(tree, pinfo, ek, usage, cryptotvb);
+
+                               /* return a private g_malloced blob to the caller */
+                               user_data=data.data;
+                               if (datalen) {
+                                       *datalen = data.length;
+                               }
+                               return user_data;
+                       }
+
+                       krb5_free_keyblock(krb5_ctx, k);
+               }
+#endif
+
                key.key.enctype=ek->keytype;
                key.key.length=ek->keylength;
                key.key.contents=ek->keyvalue;
@@ -414,9 +698,7 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
                if(ret == 0){
                        char *user_data;
 
-                       expert_add_info_format(pinfo, NULL, &ei_kerberos_decrypted_keytype,
-                                                                  "Decrypted keytype %d in frame %u using %s",
-                                                                  ek->keytype, pinfo->num, ek->key_origin);
+                       used_encryption_key(tree, pinfo, ek, usage, cryptotvb);
 
                        user_data=data.data;
                        if (datalen) {
@@ -430,10 +712,116 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
 }
 USES_APPLE_RST
 
+extern krb5_error_code
+krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
+
+static void
+verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb)
+{
+       krb5_error_code ret;
+       enc_key_t *ek = NULL;;
+       krb5_data checksum_data = {0,0,NULL};
+       krb5_cksumtype server_checksum = 0;
+       krb5_cksumtype kdc_checksum = 0;
+       int length = tvb_captured_length(pactvb);
+       const guint8 *pacbuffer = NULL;
+       krb5_pac pac;
+
+       /* don't do anything if we are not attempting to decrypt data */
+       if(!krb_decrypt || length < 1){
+               return;
+       }
+
+       /* make sure we have all the data we need */
+       if (tvb_captured_length(pactvb) < tvb_reported_length(pactvb)) {
+               return;
+       }
+
+       pacbuffer = tvb_get_ptr(pactvb, 0, length);
+
+       ret = krb5_pac_parse(krb5_ctx, pacbuffer, length, &pac);
+       if (ret != 0) {
+               proto_tree_add_expert_format(tree, actx->pinfo, &ei_kerberos_decrypted_keytype,
+                                            pactvb, 0, 0,
+                                            "Failed to parse PAC buffer %d in frame %u",
+                                            ret, actx->pinfo->fd->num);
+               return;
+       }
+
+       ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_SERVER_CHECKSUM,
+                                 &checksum_data);
+       if (ret == 0) {
+               server_checksum = pletoh32(checksum_data.data);
+               krb5_free_data_contents(krb5_ctx, &checksum_data);
+       };
+       ret = krb5_pac_get_buffer(krb5_ctx, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
+                                 &checksum_data);
+       if (ret == 0) {
+               kdc_checksum = pletoh32(checksum_data.data);
+               krb5_free_data_contents(krb5_ctx, &checksum_data);
+       };
+
+       read_keytab_file_from_preferences();
+
+       for(ek=enc_key_list;ek;ek=ek->next){
+               krb5_keyblock keyblock;
+               krb5_cksumtype checksumtype = 0;
+
+               if (server_checksum == 0 && kdc_checksum == 0) {
+                       break;
+               }
+
+               ret = krb5int_c_mandatory_cksumtype(krb5_ctx, ek->keytype,
+                                                   &checksumtype);
+               if (ret != 0) {
+                       continue;
+               }
+
+               keyblock.magic = KV5M_KEYBLOCK;
+               keyblock.enctype = ek->keytype;
+               keyblock.length = ek->keylength;
+               keyblock.contents = (guint8 *)ek->keyvalue;
+
+               if (checksumtype == server_checksum) {
+                       ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL,
+                                             &keyblock, NULL);
+                       if (ret == 0) {
+                               used_signing_key(tree, actx->pinfo, ek, pactvb,
+                                                server_checksum, "Verified Server");
+                               server_checksum = 0;
+                       }
+               }
+
+               if (checksumtype == kdc_checksum) {
+                       ret = krb5_pac_verify(krb5_ctx, pac, 0, NULL,
+                                             NULL, &keyblock);
+                       if (ret == 0) {
+                               used_signing_key(tree, actx->pinfo, ek, pactvb,
+                                                kdc_checksum, "Verified KDC");
+                               kdc_checksum = 0;
+                       }
+               }
+
+       }
+
+       krb5_pac_free(krb5_ctx, pac);
+}
+
 #elif defined(HAVE_HEIMDAL_KERBEROS)
 static krb5_context krb5_ctx;
 
 USES_APPLE_DEPRECATED_API
+
+static void
+krb5_fast_key(packet_info *pinfo,
+             const enc_key_t *ek1, const char *p1,
+             const enc_key_t *ek2, const char *p2,
+             const char *origin)
+{
+#ifdef HAVE_KRB5_CRYPTO_FX_CF2
+/* TODO */
+#endif
+}
 void
 read_keytab_file(const char *filename)
 {
@@ -471,14 +859,15 @@ read_keytab_file(const char *filename)
        }
 
        do{
-               new_key = (enc_key_t *)g_malloc(sizeof(enc_key_t));
-               new_key->fd_num = -1;
-               new_key->next=enc_key_list;
                ret = krb5_kt_next_entry(krb5_ctx, keytab, &key, &cursor);
                if(ret==0){
                        unsigned int i;
                        char *pos;
 
+                       new_key = g_new0(enc_key_t, 1);
+                       new_key->fd_num = -1;
+                       new_key->next = enc_key_list;
+
                        /* generate origin string, describing where this key came from */
                        pos=new_key->key_origin;
                        pos+=MIN(KRB_MAX_ORIG_LEN,
@@ -494,12 +883,21 @@ read_keytab_file(const char *filename)
                        new_key->keylength=(int)key.keyblock.keyvalue.length;
                        new_key->keyvalue = (guint8 *)g_memdup(key.keyblock.keyvalue.data, (guint)key.keyblock.keyvalue.length);
                        enc_key_list=new_key;
+                       ret = krb5_kt_free_entry(krb5_ctx, &key);
+                       if (ret) {
+                               fprintf(stderr, "KERBEROS ERROR: Could not release the entry: %d", ret);
+                               ret = 0; /* try to continue with the next entry */
+                       }
                }
        }while(ret==0);
 
        ret = krb5_kt_end_seq_get(krb5_ctx, keytab, &cursor);
        if(ret){
-               krb5_kt_close(krb5_ctx, keytab);
+               fprintf(stderr, "KERBEROS ERROR: Could not release the keytab cursor: %d", ret);
+       }
+       ret = krb5_kt_close(krb5_ctx, keytab);
+       if(ret){
+               fprintf(stderr, "KERBEROS ERROR: Could not close the key table handle: %d", ret);
        }
 
 }
@@ -563,9 +961,10 @@ decrypt_krb5_data(proto_tree *tree _U_, packet_info *pinfo,
                if((ret == 0) && (length>0)){
                        char *user_data;
 
-                       expert_add_info_format(pinfo, NULL, &ei_kerberos_decrypted_keytype,
-                                                                  "Decrypted keytype %d in frame %u using %s",
-                                                                  ek->keytype, pinfo->num, ek->key_origin);
+                       proto_tree_add_expert_format(tree, pinfo, &ei_kerberos_decrypted_keytype,
+                                                    NULL, 0, 0,
+                                                    "Decrypted keytype %d in frame %u using %s",
+                                                    ek->keytype, pinfo->num, ek->key_origin);
 
                        krb5_crypto_destroy(krb5_ctx, crypto);
                        /* return a private wmem_alloced blob to the caller */
@@ -600,7 +999,7 @@ add_encryption_key(packet_info *pinfo, int keytype, int keylength, const char *k
 {
        service_key_t *new_key;
 
-       if(pinfo->fd->flags.visited){
+       if(pinfo->fd->visited){
                return;
        }
 
@@ -821,58 +1220,6 @@ decrypt_krb5_data(proto_tree *tree, packet_info *pinfo,
  * unless it's expired.
  */
 
-/* pre-authentication type constants */
-#define KRB5_PA_TGS_REQ                        1
-#define KRB5_PA_ENC_TIMESTAMP          2
-#define KRB5_PA_PW_SALT                        3
-#define KRB5_PA_ENC_ENCKEY             4
-#define KRB5_PA_ENC_UNIX_TIME          5
-#define KRB5_PA_ENC_SANDIA_SECURID     6
-#define KRB5_PA_SESAME                 7
-#define KRB5_PA_OSF_DCE                        8
-#define KRB5_PA_CYBERSAFE_SECUREID     9
-#define KRB5_PA_AFS3_SALT              10
-#define KRB5_PA_ENCTYPE_INFO           11
-#define KRB5_PA_SAM_CHALLENGE          12
-#define KRB5_PA_SAM_RESPONSE           13
-#define KRB5_PA_PK_AS_REQ              14
-#define KRB5_PA_PK_AS_REP              15
-#define KRB5_PA_DASS                   16
-#define KRB5_PA_PK_AS_REP_17           17
-#define KRB5_PA_ENCTYPE_INFO2          19
-#define KRB5_PA_USE_SPECIFIED_KVNO     20
-#define KRB5_PA_SAM_REDIRECT           21
-#define KRB5_PA_GET_FROM_TYPED_DATA    22
-#define KRB5_PA_SAM_ETYPE_INFO         23
-#define KRB5_PA_ALT_PRINC              24
-#define KRB5_PA_SAM_CHALLENGE2         30
-#define KRB5_PA_SAM_RESPONSE2          31
-#define KRB5_TD_PKINIT_CMS_CERTIFICATES        101
-#define KRB5_TD_KRB_PRINCIPAL          102
-#define KRB5_TD_KRB_REALM              103
-#define KRB5_TD_TRUSTED_CERTIFIERS     104
-#define KRB5_TD_CERTIFICATE_INDEX      105
-#define KRB5_TD_APP_DEFINED_ERROR      106
-#define KRB5_TD_REQ_NONCE              107
-#define KRB5_TD_REQ_SEQ                        108
-/* preauthentication types >127 (i.e. negative ones) are app specific.
-   however since Microsoft is the dominant(only?) user of types in this range
-   we also treat the type as unsigned.
-*/
-#define KRB5_PA_PAC_REQUEST            128    /* (Microsoft extension) */
-#define KRB5_PA_FOR_USER               129    /* Impersonation (Microsoft extension) See [MS-SFU]. XXX - replaced by KRB5_PA_S4U2SELF */
-#define KRB5_PA_S4U2SELF               129
-#define KRB5_PADATA_S4U_X509_USER      130 /* certificate protocol transition request */
-#define KRB5_PADATA_FX_COOKIE  133
-#define KRB5_PA_AUTHENTICATION_SET 134
-#define KRB5_PADATA_FX_FAST            136
-#define KRB5_PADATA_FX_ERROR   137
-#define KRB5_PADATA_ENCRYPTED_CHALLENGE        138
-#define KRB5_PADATA_PKINIT_KX  147
-#define KRB5_ENCPADATA_REQ_ENC_PA_REP  149
-
-
-#define KRB5_PA_PROV_SRV_LOCATION 0xffffffff    /* (gint32)0xFF) packetcable stuff */
 /* Principal name-type */
 #define KRB5_NT_UNKNOWN                0
 #define KRB5_NT_PRINCIPAL      1
@@ -966,6 +1313,10 @@ decrypt_krb5_data(proto_tree *tree, packet_info *pinfo,
 #define KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNAVAILABLE  74
 #define KRB5_ET_KDC_ERR_CLIENT_NAME_MISMATCH           75
 #define KRB5_ET_KDC_ERR_KDC_NAME_MISMATCH              76
+#define KRB5_ET_KDC_ERR_PREAUTH_EXPIRED                        90
+#define KRB5_ET_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED     91
+#define KRB5_ET_KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92
+#define KRB5_ET_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS  93
 
 static const value_string krb5_error_codes[] = {
        { KRB5_ET_KRB5KDC_ERR_NONE, "KRB5KDC_ERR_NONE" },
@@ -1037,6 +1388,10 @@ static const value_string krb5_error_codes[] = {
        { KRB5_ET_KDC_ERR_REVOCATION_STATUS_UNAVAILABLE, "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE" },
        { KRB5_ET_KDC_ERR_CLIENT_NAME_MISMATCH, "KDC_ERR_CLIENT_NAME_MISMATCH" },
        { KRB5_ET_KDC_ERR_KDC_NAME_MISMATCH, "KDC_ERR_KDC_NAME_MISMATCH" },
+       { KRB5_ET_KDC_ERR_PREAUTH_EXPIRED, "KDC_ERR_PREAUTH_EXPIRED" },
+       { KRB5_ET_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED, "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED" },
+       { KRB5_ET_KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET, "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET" },
+       { KRB5_ET_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS" },
        { 0, NULL }
 };
 
@@ -1047,124 +1402,24 @@ static const value_string krb5_error_codes[] = {
 #define PAC_PRIVSVR_CHECKSUM   7
 #define PAC_CLIENT_INFO_TYPE   10
 #define PAC_S4U_DELEGATION_INFO        11
-#define PAC_UPN_DNS_INFO               12
+#define PAC_UPN_DNS_INFO       12
+#define PAC_CLIENT_CLAIMS_INFO 13
+#define PAC_DEVICE_INFO                14
+#define PAC_DEVICE_CLAIMS_INFO 15
 static const value_string w2k_pac_types[] = {
        { PAC_LOGON_INFO                , "Logon Info" },
-       { PAC_CREDENTIAL_TYPE   , "Credential Type" },
-       { PAC_SERVER_CHECKSUM   , "Server Checksum" },
-       { PAC_PRIVSVR_CHECKSUM  , "Privsvr Checksum" },
-       { PAC_CLIENT_INFO_TYPE  , "Client Info Type" },
-       { PAC_S4U_DELEGATION_INFO, "S4U Delegation Info" },
+       { PAC_CREDENTIAL_TYPE           , "Credential Type" },
+       { PAC_SERVER_CHECKSUM           , "Server Checksum" },
+       { PAC_PRIVSVR_CHECKSUM          , "Privsvr Checksum" },
+       { PAC_CLIENT_INFO_TYPE          , "Client Info Type" },
+       { PAC_S4U_DELEGATION_INFO       , "S4U Delegation Info" },
        { PAC_UPN_DNS_INFO              , "UPN DNS Info" },
+       { PAC_CLIENT_CLAIMS_INFO        , "Client Claims Info" },
+       { PAC_DEVICE_INFO               , "Device Info" },
+       { PAC_DEVICE_CLAIMS_INFO        , "Device Claims Info" },
        { 0, NULL },
 };
 
-#if 0
-static const value_string krb5_princ_types[] = {
-       { KRB5_NT_UNKNOWN              , "Unknown" },
-       { KRB5_NT_PRINCIPAL            , "Principal" },
-       { KRB5_NT_SRV_INST             , "Service and Instance" },
-       { KRB5_NT_SRV_HST              , "Service and Host" },
-       { KRB5_NT_SRV_XHST             , "Service and Host Components" },
-       { KRB5_NT_UID                  , "Unique ID" },
-       { KRB5_NT_X500_PRINCIPAL       , "Encoded X.509 Distinguished Name" },
-       { KRB5_NT_SMTP_NAME            , "SMTP Name" },
-       { KRB5_NT_ENTERPRISE           , "Enterprise Name" },
-       { KRB5_NT_MS_PRINCIPAL         , "NT 4.0 style name (MS specific)" },
-       { KRB5_NT_MS_PRINCIPAL_AND_SID , "NT 4.0 style name with SID (MS specific)"},
-       { KRB5_NT_ENT_PRINCIPAL_AND_SID, "UPN and SID (MS specific)"},
-       { KRB5_NT_PRINCIPAL_AND_SID    , "Principal name and SID (MS specific)"},
-       { KRB5_NT_SRV_INST_AND_SID     , "SPN and SID (MS specific)"},
-       { 0                            , NULL },
-};
-#endif
-
-static const value_string krb5_preauthentication_types[] = {
-       { KRB5_PA_TGS_REQ              , "PA-TGS-REQ" },
-       { KRB5_PA_ENC_TIMESTAMP        , "PA-ENC-TIMESTAMP" },
-       { KRB5_PA_PW_SALT              , "PA-PW-SALT" },
-       { KRB5_PA_ENC_ENCKEY           , "PA-ENC-ENCKEY" },
-       { KRB5_PA_ENC_UNIX_TIME        , "PA-ENC-UNIX-TIME" },
-       { KRB5_PA_ENC_SANDIA_SECURID   , "PA-PW-SALT" },
-       { KRB5_PA_SESAME               , "PA-SESAME" },
-       { KRB5_PA_OSF_DCE              , "PA-OSF-DCE" },
-       { KRB5_PA_CYBERSAFE_SECUREID   , "PA-CYBERSAFE-SECURID" },
-       { KRB5_PA_AFS3_SALT            , "PA-AFS3-SALT" },
-       { KRB5_PA_ENCTYPE_INFO         , "PA-ENCTYPE-INFO" },
-       { KRB5_PA_ENCTYPE_INFO2         , "PA-ENCTYPE-INFO2" },
-       { KRB5_PA_SAM_CHALLENGE        , "PA-SAM-CHALLENGE" },
-       { KRB5_PA_SAM_RESPONSE         , "PA-SAM-RESPONSE" },
-       { KRB5_PA_PK_AS_REQ            , "PA-PK-AS-REQ" },
-       { KRB5_PA_PK_AS_REP            , "PA-PK-AS-REP" },
-       { KRB5_PA_DASS                 , "PA-DASS" },
-       { KRB5_PA_PK_AS_REP_17         , "PA-PK-AS-REP-17" },
-       { KRB5_PA_USE_SPECIFIED_KVNO   , "PA-USE-SPECIFIED-KVNO" },
-       { KRB5_PA_SAM_REDIRECT         , "PA-SAM-REDIRECT" },
-       { KRB5_PA_GET_FROM_TYPED_DATA  , "PA-GET-FROM-TYPED-DATA" },
-       { KRB5_PA_SAM_ETYPE_INFO       , "PA-SAM-ETYPE-INFO" },
-       { KRB5_PA_ALT_PRINC            , "PA-ALT-PRINC" },
-       { KRB5_PA_SAM_CHALLENGE2       , "PA-SAM-CHALLENGE2" },
-       { KRB5_PA_SAM_RESPONSE2        , "PA-SAM-RESPONSE2" },
-       { KRB5_TD_PKINIT_CMS_CERTIFICATES, "TD-PKINIT-CMS-CERTIFICATES" },
-       { KRB5_TD_KRB_PRINCIPAL        , "TD-KRB-PRINCIPAL" },
-       { KRB5_TD_KRB_REALM , "TD-KRB-REALM" },
-       { KRB5_TD_TRUSTED_CERTIFIERS   , "TD-TRUSTED-CERTIFIERS" },
-       { KRB5_TD_CERTIFICATE_INDEX    , "TD-CERTIFICATE-INDEX" },
-       { KRB5_TD_APP_DEFINED_ERROR    , "TD-APP-DEFINED-ERROR" },
-       { KRB5_TD_REQ_NONCE            , "TD-REQ-NONCE" },
-       { KRB5_TD_REQ_SEQ              , "TD-REQ-SEQ" },
-       { KRB5_PA_PAC_REQUEST          , "PA-PAC-REQUEST" },
-       { KRB5_PA_FOR_USER             , "PA-FOR-USER" },
-       { KRB5_PADATA_S4U_X509_USER    , "PA-S4U-X509-USER" },
-       { KRB5_PADATA_FX_COOKIE        , "PA-FX-COOKIE" },
-       { KRB5_PA_AUTHENTICATION_SET   , "KRB5-PA-AUTHENTICATION-SET" },
-
-       { KRB5_PADATA_FX_FAST          , "PA-FX-FAST" },
-       { KRB5_PADATA_FX_ERROR         , "PA-FX-ERROR" },
-       { KRB5_PADATA_ENCRYPTED_CHALLENGE , "PA-ENCRYPTED-CHALLENGE" },
-       { KRB5_PADATA_PKINIT_KX        , "PA-PKINIT-KX" },
-       { KRB5_ENCPADATA_REQ_ENC_PA_REP , "PA-REQ-ENC-PA-REP" },
-       { KRB5_PA_PROV_SRV_LOCATION    , "PA-PROV-SRV-LOCATION" },
-       { 0                            , NULL },
-};
-
-#define KRB5_AD_IF_RELEVANT                    1
-#define KRB5_AD_INTENDED_FOR_SERVER            2
-#define KRB5_AD_INTENDED_FOR_APPLICATION_CLASS 3
-#define KRB5_AD_KDC_ISSUED                     4
-#define KRB5_AD_OR                             5
-#define KRB5_AD_MANDATORY_TICKET_EXTENSIONS    6
-#define KRB5_AD_IN_TICKET_EXTENSIONS           7
-#define KRB5_AD_MANDATORY_FOR_KDC              8
-#define KRB5_AD_OSF_DCE                                64
-#define KRB5_AD_SESAME                         65
-#define KRB5_AD_OSF_DCE_PKI_CERTID             66
-#define KRB5_AD_WIN2K_PAC                              128
-#define KRB5_AD_SIGNTICKET                     0xffffffef
-
-static const value_string krb5_ad_types[] = {
-       { KRB5_AD_IF_RELEVANT                   , "AD-IF-RELEVANT" },
-       { KRB5_AD_INTENDED_FOR_SERVER           , "AD-Intended-For-Server" },
-       { KRB5_AD_INTENDED_FOR_APPLICATION_CLASS        , "AD-Intended-For-Application-Class" },
-       { KRB5_AD_KDC_ISSUED                    , "AD-KDCIssued" },
-       { KRB5_AD_OR                            , "AD-AND-OR" },
-       { KRB5_AD_MANDATORY_TICKET_EXTENSIONS   , "AD-Mandatory-Ticket-Extensions" },
-       { KRB5_AD_IN_TICKET_EXTENSIONS          , "AD-IN-Ticket-Extensions" },
-       { KRB5_AD_MANDATORY_FOR_KDC                     , "AD-MANDATORY-FOR-KDC" },
-       { KRB5_AD_OSF_DCE                               , "AD-OSF-DCE" },
-       { KRB5_AD_SESAME                                , "AD-SESAME" },
-       { KRB5_AD_OSF_DCE_PKI_CERTID            , "AD-OSF-DCE-PKI-CertID" },
-       { KRB5_AD_WIN2K_PAC                             , "AD-Win2k-PAC" },
-       { KRB5_AD_SIGNTICKET                    , "AD-SignTicket" },
-       { 0     , NULL },
-};
-#if 0
-static const value_string krb5_transited_types[] = {
-       { 1                           , "DOMAIN-X500-COMPRESS" },
-       { 0                           , NULL }
-};
-#endif
-
 static const value_string krb5_msg_types[] = {
        { KRB5_MSG_TICKET,              "Ticket" },
        { KRB5_MSG_AUTHENTICATOR,       "Authenticator" },
@@ -1292,6 +1547,42 @@ dissect_krb5_decrypt_authenticator_data (gboolean imp_tag _U_, tvbuff_t *tvb, in
        return offset;
 }
 
+static int
+dissect_krb5_decrypt_authorization_data(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
+                                       proto_tree *tree, int hf_index _U_)
+{
+       guint8 *plaintext;
+       int length;
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+       tvbuff_t *next_tvb;
+
+       next_tvb=tvb_new_subset_remaining(tvb, offset);
+       length=tvb_captured_length_remaining(tvb, offset);
+
+       /* draft-ietf-krb-wg-kerberos-clarifications-05.txt :
+        * 7.5.1
+        * Authenticators are encrypted with usage
+        * == 5 or
+        * == 4
+        */
+       plaintext=decrypt_krb5_data(tree, actx->pinfo, 5, next_tvb, private_data->etype, NULL);
+
+       if(!plaintext){
+               plaintext=decrypt_krb5_data(tree, actx->pinfo, 4, next_tvb, private_data->etype, NULL);
+       }
+
+       if(plaintext){
+               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, "Decrypted Krb5");
+
+               offset=dissect_kerberos_AuthorizationData(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
+       }
+       return offset;
+}
+
 static int
 dissect_krb5_decrypt_KDC_REP_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
                                                                        proto_tree *tree, int hf_index _U_)
@@ -1359,7 +1650,7 @@ dissect_krb5_decrypt_PA_ENC_TIMESTAMP (gboolean imp_tag _U_, tvbuff_t *tvb, int
                /* Add the decrypted data to the data source list. */
                add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
 
-               offset=dissect_kerberos_Applications(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
+               offset=dissect_kerberos_PA_ENC_TS_ENC(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
        }
        return offset;
 }
@@ -1453,8 +1744,163 @@ dissect_krb5_decrypt_CRED_data (gboolean imp_tag _U_, tvbuff_t *tvb, int offset,
        }
        return offset;
 }
+
+static int
+dissect_krb5_decrypt_KrbFastReq(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
+                               proto_tree *tree, int hf_index _U_)
+{
+       guint8 *plaintext;
+       int length;
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+       tvbuff_t *next_tvb;
+
+       next_tvb=tvb_new_subset_remaining(tvb, offset);
+       length=tvb_captured_length_remaining(tvb, offset);
+
+       /* RFC6113 :
+        * KrbFastResponse encrypted with usage
+        * KEY_USAGE_FAST_ENC 51
+        */
+       plaintext=decrypt_krb5_data(tree, actx->pinfo, KEY_USAGE_FAST_ENC,
+                                   next_tvb, private_data->etype, NULL);
+
+       if(plaintext){
+               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, "Decrypted Krb5");
+
+               offset=dissect_kerberos_KrbFastReq(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
+       }
+       return offset;
+}
+
+static int
+dissect_krb5_decrypt_KrbFastResponse(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
+                                    proto_tree *tree, int hf_index _U_)
+{
+       guint8 *plaintext;
+       int length;
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+       tvbuff_t *next_tvb;
+
+       next_tvb=tvb_new_subset_remaining(tvb, offset);
+       length=tvb_captured_length_remaining(tvb, offset);
+
+       /*
+        * RFC6113 :
+        * KrbFastResponse encrypted with usage
+        * KEY_USAGE_FAST_REP 52
+        */
+       plaintext=decrypt_krb5_data(tree, actx->pinfo, KEY_USAGE_FAST_REP,
+                                   next_tvb, private_data->etype, NULL);
+
+       if(plaintext){
+               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, "Decrypted Krb5");
+
+               private_data->fast_armor_key = private_data->last_decryption_key;
+               offset=dissect_kerberos_KrbFastResponse(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
+       }
+       return offset;
+}
+
+static int
+dissect_krb5_decrypt_EncryptedChallenge(gboolean imp_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx,
+                                       proto_tree *tree, int hf_index _U_)
+{
+       guint8 *plaintext;
+       int length;
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+       tvbuff_t *next_tvb;
+       int usage = 0;
+
+       next_tvb=tvb_new_subset_remaining(tvb, offset);
+       length=tvb_captured_length_remaining(tvb, offset);
+
+       /* RFC6113 :
+        * KEY_USAGE_ENC_CHALLENGE_CLIENT  54
+        * KEY_USAGE_ENC_CHALLENGE_KDC     55
+        */
+       if (private_data->kdc_response) {
+               usage = KEY_USAGE_ENC_CHALLENGE_KDC;
+       } else {
+               usage = KEY_USAGE_ENC_CHALLENGE_CLIENT;
+       }
+       plaintext=decrypt_krb5_data(tree, actx->pinfo, usage, next_tvb, private_data->etype, NULL);
+
+       if(plaintext){
+               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, "Decrypted Krb5");
+
+               offset=dissect_kerberos_PA_ENC_TS_ENC(FALSE, child_tvb, 0, actx , tree, /* hf_index*/ -1);
+       }
+       return offset;
+}
 #endif
 
+static const int *hf_krb_pa_supported_enctypes_fields[] = {
+       &hf_krb_pa_supported_enctypes_des_cbc_crc,
+       &hf_krb_pa_supported_enctypes_des_cbc_md5,
+       &hf_krb_pa_supported_enctypes_rc4_hmac,
+       &hf_krb_pa_supported_enctypes_aes128_cts_hmac_sha1_96,
+       &hf_krb_pa_supported_enctypes_aes256_cts_hmac_sha1_96,
+       &hf_krb_pa_supported_enctypes_fast_supported,
+       &hf_krb_pa_supported_enctypes_compound_identity_supported,
+       &hf_krb_pa_supported_enctypes_claims_supported,
+       &hf_krb_pa_supported_enctypes_resource_sid_compression_disabled,
+       NULL,
+};
+
+static const true_false_string supported_tfs = {
+       "Supported", "Not supported"
+};
+
+static int
+dissect_kerberos_PA_SUPPORTED_ENCTYPES(gboolean implicit_tag _U_, tvbuff_t *tvb _U_,
+                                      int offset _U_, asn1_ctx_t *actx _U_,
+                                      proto_tree *tree _U_, int hf_index _U_)
+{
+       actx->created_item = proto_tree_add_bitmask(tree, tvb, offset,
+                                                   hf_krb_pa_supported_enctypes,
+                                                   ett_krb_pa_supported_enctypes,
+                                                   hf_krb_pa_supported_enctypes_fields,
+                                                   ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       return offset;
+}
+
+static const int *hf_krb_ad_ap_options_fields[] = {
+       &hf_krb_ad_ap_options_cbt,
+       NULL,
+};
+
+static const true_false_string set_tfs = {
+       "Set", "Not set"
+};
+
+static int
+dissect_kerberos_AD_AP_OPTIONS(gboolean implicit_tag _U_, tvbuff_t *tvb _U_,
+                              int offset _U_, asn1_ctx_t *actx _U_,
+                              proto_tree *tree _U_, int hf_index _U_)
+{
+       actx->created_item = proto_tree_add_bitmask(tree, tvb, offset,
+                                                   hf_krb_ad_ap_options,
+                                                   ett_krb_ad_ap_options,
+                                                   hf_krb_ad_ap_options_fields,
+                                                   ENC_LITTLE_ENDIAN);
+       offset += 4;
+
+       return offset;
+}
 /* Dissect a GSSAPI checksum as per RFC1964. This is NOT ASN.1 encoded.
  */
 static int
@@ -1524,15 +1970,36 @@ dissect_krb5_PA_PROV_SRV_LOCATION(gboolean implicit_tag _U_, tvbuff_t *tvb _U_,
 static int
 dissect_krb5_PW_SALT(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)
 {
-       guint32 nt_status;
+       kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
+       gint remaining = tvb_reported_length_remaining(tvb, offset);
+       guint32 nt_status = 0;
+       guint32 val_0 = 0;
+       guint32 val_1 = 0;
+
+       if (private_data->errorcode == 0) {
+               goto no_error;
+       }
+
+       if (!private_data->try_nt_status) {
+               goto no_error;
+       }
+
+       if (remaining != 12) {
+               goto no_error;
+       }
+
+       nt_status=tvb_get_letohl(tvb, offset);
+       val_0=tvb_get_letohl(tvb, offset + 4);
+       val_1=tvb_get_letohl(tvb, offset + 8);
+
+       if (val_0 != 0 || val_1 != 1) {
+               goto no_error;
+       }
 
        /* Microsoft stores a special 12 byte blob here
         * guint32 NT_status
-        * guint32 unknown
-        * guint32 unknown
-        * decode everything as this blob for now until we see if anyone
-        * else ever uses it   or we learn how to tell whether this
-        * is such an MS blob or not.
+        * guint32 unknown (== 0)
+        * guint32 unknown (== 1)
         */
        proto_tree_add_item(tree, hf_krb_smb_nt_status, tvb, offset, 4,
                        ENC_LITTLE_ENDIAN);
@@ -1554,6 +2021,9 @@ dissect_krb5_PW_SALT(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U
        offset += 4;
 
        return offset;
+
+ no_error:
+       return offset + remaining;
 }
 
 static int
@@ -1640,6 +2110,61 @@ dissect_krb5_PAC_LOGON_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset,
        return offset;
 }
 
+
+static int
+dissect_krb5_PAC_CREDENTIAL_DATA(proto_tree *parent_tree, tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
+{
+       proto_tree_add_item(parent_tree, hf_krb_pac_credential_data, tvb, offset, -1, ENC_NA);
+
+       return offset;
+}
+
+static int
+dissect_krb5_PAC_CREDENTIAL_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx)
+{
+       proto_item *item;
+       proto_tree *tree;
+       guint32 etype;
+       guint8 *plaintext = NULL;
+       int plainlen = 0;
+       int length;
+       tvbuff_t *next_tvb;
+#define KRB5_KU_OTHER_ENCRYPTED 16
+       int usage = KRB5_KU_OTHER_ENCRYPTED;
+
+       item = proto_tree_add_item(parent_tree, hf_krb_pac_credential_info, tvb, offset, -1, ENC_NA);
+       tree = proto_item_add_subtree(item, ett_krb_pac_credential_info);
+
+       /* version */
+       proto_tree_add_item(tree, hf_krb_pac_credential_info_version, tvb,
+                           offset, 4, ENC_LITTLE_ENDIAN);
+       offset+=4;
+
+       /* etype */
+       etype = tvb_get_letohl(tvb, offset);
+       proto_tree_add_item(tree, hf_krb_pac_credential_info_etype, tvb,
+                           offset, 4, ENC_LITTLE_ENDIAN);
+       offset+=4;
+
+       /* data */
+       next_tvb=tvb_new_subset_remaining(tvb, offset);
+       length=tvb_captured_length_remaining(tvb, offset);
+
+       plaintext=decrypt_krb5_data(tree, actx->pinfo, usage, next_tvb, (int)etype, &plainlen);
+
+       if (plaintext != NULL) {
+               tvbuff_t *child_tvb;
+               child_tvb = tvb_new_child_real_data(tvb, plaintext, plainlen, plainlen);
+
+               /* Add the decrypted data to the data source list. */
+               add_new_data_source(actx->pinfo, child_tvb, "Decrypted Krb5");
+
+               dissect_krb5_PAC_CREDENTIAL_DATA(tree, child_tvb, 0, actx->pinfo);
+       }
+
+       return offset + length;
+}
+
 static int
 dissect_krb5_PAC_S4U_DELEGATION_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx)
 {
@@ -1722,9 +2247,25 @@ dissect_krb5_PAC_UPN_DNS_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset
 }
 
 static int
-dissect_krb5_PAC_CREDENTIAL_TYPE(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
+dissect_krb5_PAC_CLIENT_CLAIMS_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
+{
+       proto_tree_add_item(parent_tree, hf_krb_pac_client_claims_info, tvb, offset, -1, ENC_NA);
+
+       return offset;
+}
+
+static int
+dissect_krb5_PAC_DEVICE_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
+{
+       proto_tree_add_item(parent_tree, hf_krb_pac_device_info, tvb, offset, -1, ENC_NA);
+
+       return offset;
+}
+
+static int
+dissect_krb5_PAC_DEVICE_CLAIMS_INFO(proto_tree *parent_tree, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_)
 {
-       proto_tree_add_item(parent_tree, hf_krb_pac_credential_type, tvb, offset, -1, ENC_NA);
+       proto_tree_add_item(parent_tree, hf_krb_pac_device_claims_info, tvb, offset, -1, ENC_NA);
 
        return offset;
 }
@@ -1825,7 +2366,7 @@ dissect_krb5_AD_WIN2K_PAC_struct(proto_tree *tree, tvbuff_t *tvb, int offset, as
                dissect_krb5_PAC_LOGON_INFO(tr, next_tvb, 0, actx);
                break;
        case PAC_CREDENTIAL_TYPE:
-               dissect_krb5_PAC_CREDENTIAL_TYPE(tr, next_tvb, 0, actx);
+               dissect_krb5_PAC_CREDENTIAL_INFO(tr, next_tvb, 0, actx);
                break;
        case PAC_SERVER_CHECKSUM:
                dissect_krb5_PAC_SERVER_CHECKSUM(tr, next_tvb, 0, actx);
@@ -1842,6 +2383,15 @@ dissect_krb5_AD_WIN2K_PAC_struct(proto_tree *tree, tvbuff_t *tvb, int offset, as
        case PAC_UPN_DNS_INFO:
                dissect_krb5_PAC_UPN_DNS_INFO(tr, next_tvb, 0, actx);
                break;
+       case PAC_CLIENT_CLAIMS_INFO:
+               dissect_krb5_PAC_CLIENT_CLAIMS_INFO(tr, next_tvb, 0, actx);
+               break;
+       case PAC_DEVICE_INFO:
+               dissect_krb5_PAC_DEVICE_INFO(tr, next_tvb, 0, actx);
+               break;
+       case PAC_DEVICE_CLAIMS_INFO:
+               dissect_krb5_PAC_DEVICE_CLAIMS_INFO(tr, next_tvb, 0, actx);
+               break;
 
        default:
                break;
@@ -1856,6 +2406,10 @@ dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset,
        guint32 version;
        guint32 i;
 
+#ifdef HAVE_KERBEROS
+       verify_krb5_pac(tree, actx, tvb);
+#endif
+
        /* first in the PAC structure comes the number of entries */
        entries=tvb_get_letohl(tvb, offset);
        proto_tree_add_uint(tree, hf_krb_w2k_pac_entries, tvb, offset, 4, entries);
@@ -1976,10 +2530,10 @@ dissect_kerberos_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        default:
                                return 0;
                }
-       if (do_col_protocol) {
+               if (do_col_protocol) {
                        col_set_str(pinfo->cinfo, COL_PROTOCOL, "KRB5");
-       }
-       if (gbl_do_col_info) {
+               }
+               if (gbl_do_col_info) {
                        col_clear(pinfo->cinfo, COL_INFO);
                }
                if (tree) {
@@ -2214,9 +2768,18 @@ void proto_register_kerberos(void) {
        { &hf_krb_pac_logon_info, {
                "PAC_LOGON_INFO", "kerberos.pac_logon_info", FT_BYTES, BASE_NONE,
                NULL, 0, "PAC_LOGON_INFO structure", HFILL }},
-       { &hf_krb_pac_credential_type, {
-               "PAC_CREDENTIAL_TYPE", "kerberos.pac_credential_type", FT_BYTES, BASE_NONE,
-               NULL, 0, "PAC_CREDENTIAL_TYPE structure", HFILL }},
+       { &hf_krb_pac_credential_data, {
+               "PAC_CREDENTIAL_DATA", "kerberos.pac_credential_data", FT_BYTES, BASE_NONE,
+               NULL, 0, "PAC_CREDENTIAL_DATA structure", HFILL }},
+       { &hf_krb_pac_credential_info, {
+               "PAC_CREDENTIAL_INFO", "kerberos.pac_credential_info", FT_BYTES, BASE_NONE,
+               NULL, 0, "PAC_CREDENTIAL_INFO structure", HFILL }},
+       { &hf_krb_pac_credential_info_version, {
+               "Version", "kerberos.pac_credential_info.version", FT_UINT32, BASE_DEC,
+               NULL, 0, NULL, HFILL }},
+       { &hf_krb_pac_credential_info_etype, {
+               "Etype", "kerberos.pac_credential_info.etype", FT_UINT32, BASE_DEC,
+               NULL, 0, NULL, HFILL }},
        { &hf_krb_pac_server_checksum, {
                "PAC_SERVER_CHECKSUM", "kerberos.pac_server_checksum", FT_BYTES, BASE_NONE,
                NULL, 0, "PAC_SERVER_CHECKSUM structure", HFILL }},
@@ -2253,6 +2816,51 @@ void proto_register_kerberos(void) {
        { &hf_krb_pac_upn_dns_name, {
                "DNS Name", "kerberos.pac.upn.dns_name", FT_STRING, BASE_NONE,
                NULL, 0, NULL, HFILL }},
+       { &hf_krb_pac_client_claims_info, {
+               "PAC_CLIENT_CLAIMS_INFO", "kerberos.pac_client_claims_info", FT_BYTES, BASE_NONE,
+               NULL, 0, "PAC_CLIENT_CLAIMS_INFO structure", HFILL }},
+       { &hf_krb_pac_device_info, {
+               "PAC_DEVICE_INFO", "kerberos.pac_device_info", FT_BYTES, BASE_NONE,
+               NULL, 0, "PAC_DEVICE_INFO structure", HFILL }},
+       { &hf_krb_pac_device_claims_info, {
+               "PAC_DEVICE_CLAIMS_INFO", "kerberos.pac_device_claims_info", FT_BYTES, BASE_NONE,
+               NULL, 0, "PAC_DEVICE_CLAIMS_INFO structure", HFILL }},
+       { &hf_krb_pa_supported_enctypes,
+         { "SupportedEnctypes", "kerberos.supported_entypes",
+           FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_des_cbc_crc,
+         { "des-cbc-crc", "kerberos.supported_entypes.des-cbc-crc",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00000001, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_des_cbc_md5,
+         { "des-cbc-md5", "kerberos.supported_entypes.des-cbc-md5",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00000002, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_rc4_hmac,
+         { "rc4-hmac", "kerberos.supported_entypes.rc4-hmac",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00000004, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_aes128_cts_hmac_sha1_96,
+         { "aes128-cts-hmac-sha1-96", "kerberos.supported_entypes.aes128-cts-hmac-sha1-96",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00000008, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_aes256_cts_hmac_sha1_96,
+         { "aes256-cts-hmac-sha1-96", "kerberos.supported_entypes.aes256-cts-hmac-sha1-96",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00000010, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_fast_supported,
+         { "fast-supported", "kerberos.supported_entypes.fast-supported",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00010000, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_compound_identity_supported,
+         { "compound-identity-supported", "kerberos.supported_entypes.compound-identity-supported",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00020000, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_claims_supported,
+         { "claims-supported", "kerberos.supported_entypes.claims-supported",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00040000, NULL, HFILL }},
+       { &hf_krb_pa_supported_enctypes_resource_sid_compression_disabled,
+         { "resource-sid-compression-disabled", "kerberos.supported_entypes.resource-sid-compression-disabled",
+           FT_BOOLEAN, 32, TFS(&supported_tfs), 0x00080000, NULL, HFILL }},
+       { &hf_krb_ad_ap_options,
+         { "AD-AP-Options", "kerberos.ad_ap_options",
+           FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+       { &hf_krb_ad_ap_options_cbt,
+         { "ChannelBindings", "kerberos.ad_ap_options.cbt",
+           FT_BOOLEAN, 32, TFS(&set_tfs), 0x00004000, NULL, HFILL }},
 
 #include "packet-kerberos-hfarr.c"
        };
@@ -2265,11 +2873,14 @@ void proto_register_kerberos(void) {
                &ett_krb_pac_drep,
                &ett_krb_pac_midl_blob,
                &ett_krb_pac_logon_info,
+               &ett_krb_pac_credential_info,
                &ett_krb_pac_s4u_delegation_info,
                &ett_krb_pac_upn_dns_info,
                &ett_krb_pac_server_checksum,
                &ett_krb_pac_privsvr_checksum,
                &ett_krb_pac_client_info_type,
+               &ett_krb_pa_supported_enctypes,
+               &ett_krb_ad_ap_options,
 #include "packet-kerberos-ettarr.c"
        };