forked from osmocom/wireshark
packet-kerberos: try to verify the PAC checksums and display the used keys
This makes it much easier to analyze how PAC signing is supposed to work with trusted domains. Change-Id: I9993e5d92b7efee5aa91cd0e2005787f7d384444 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-on: https://code.wireshark.org/review/35704 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>osmith/wip
parent
23a6fab52e
commit
d9aab840a7
|
@ -54,6 +54,7 @@
|
|||
#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"
|
||||
|
@ -295,6 +296,22 @@ static void used_encryption_key(proto_tree *tree, packet_info *pinfo,
|
|||
ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MIT_KERBEROS
|
||||
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);
|
||||
}
|
||||
#endif /* HAVE_MIT_KERBEROS */
|
||||
|
||||
#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
|
||||
|
||||
#if defined(HAVE_MIT_KERBEROS)
|
||||
|
@ -443,6 +460,101 @@ 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;
|
||||
|
||||
|
@ -1897,6 +2009,10 @@ dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset,
|
|||
guint32 version;
|
||||
guint32 i;
|
||||
|
||||
#ifdef HAVE_MIT_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);
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#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"
|
||||
|
@ -387,7 +388,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 173 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 174 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
|
||||
/* Initialize the subtree pointers */
|
||||
static gint ett_kerberos = -1;
|
||||
|
@ -475,7 +476,7 @@ static gint ett_kerberos_PA_FX_FAST_REPLY = -1;
|
|||
static gint ett_kerberos_KrbFastArmoredRep = -1;
|
||||
|
||||
/*--- End of included file: packet-kerberos-ett.c ---*/
|
||||
#line 187 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 188 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
|
||||
static expert_field ei_kerberos_decrypted_keytype = EI_INIT;
|
||||
static expert_field ei_kerberos_address = EI_INIT;
|
||||
|
@ -503,7 +504,7 @@ static gboolean gbl_do_col_info;
|
|||
#define KERBEROS_ADDR_TYPE_IPV6 24
|
||||
|
||||
/*--- End of included file: packet-kerberos-val.h ---*/
|
||||
#line 199 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 200 "./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)
|
||||
|
@ -598,11 +599,27 @@ static void used_encryption_key(proto_tree *tree, packet_info *pinfo,
|
|||
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->keytype, usage, pinfo->fd->num, ek->key_origin,
|
||||
ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF,
|
||||
ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MIT_KERBEROS
|
||||
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);
|
||||
}
|
||||
#endif /* HAVE_MIT_KERBEROS */
|
||||
|
||||
#endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
|
||||
|
||||
#if defined(HAVE_MIT_KERBEROS)
|
||||
|
@ -751,6 +768,101 @@ 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;
|
||||
|
||||
|
@ -2205,6 +2317,10 @@ dissect_krb5_AD_WIN2K_PAC(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset,
|
|||
guint32 version;
|
||||
guint32 i;
|
||||
|
||||
#ifdef HAVE_MIT_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);
|
||||
|
@ -4657,7 +4773,7 @@ dissect_kerberos_EncryptedChallenge(gboolean implicit_tag _U_, tvbuff_t *tvb _U_
|
|||
|
||||
|
||||
/*--- End of included file: packet-kerberos-fn.c ---*/
|
||||
#line 1918 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 2034 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
|
||||
/* Make wrappers around exported functions for now */
|
||||
int
|
||||
|
@ -5865,7 +5981,7 @@ void proto_register_kerberos(void) {
|
|||
NULL, HFILL }},
|
||||
|
||||
/*--- End of included file: packet-kerberos-hfarr.c ---*/
|
||||
#line 2305 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 2421 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
};
|
||||
|
||||
/* List of subtrees */
|
||||
|
@ -5955,7 +6071,7 @@ void proto_register_kerberos(void) {
|
|||
&ett_kerberos_KrbFastArmoredRep,
|
||||
|
||||
/*--- End of included file: packet-kerberos-ettarr.c ---*/
|
||||
#line 2321 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
#line 2437 "./asn1/kerberos/packet-kerberos-template.c"
|
||||
};
|
||||
|
||||
static ei_register_info ei[] = {
|
||||
|
|
Loading…
Reference in New Issue