packet-kerberos: add support for decrypting KRB5 FAST messages

Currently this is only available for MIT Kerberos, but it
should be possible to implement the same using
krb5_crypto_fx_cf2() from Heimdal.

Change-Id: Ic3327dfde770f9345485bf97e2ac6045b909b64e
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-on: https://code.wireshark.org/review/36472
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Stefan Metzmacher 2015-02-19 05:40:29 +01:00 committed by Anders Broman
parent a97956fa20
commit 738e73a50e
8 changed files with 1597 additions and 147 deletions

View File

@ -86,8 +86,12 @@ if(KERBEROS_FOUND)
include(CheckSymbolExists)
set(CMAKE_REQUIRED_INCLUDES ${KERBEROS_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${KERBEROS_LIBRARIES})
#see also HAVE_HEIMDAL_KERBEROS in cmakeconfig.h.in
check_symbol_exists("heimdal_version" "krb5.h" HAVE_HEIMDAL_KERBEROS)
# see also HAVE_KRB5_PAC_VERIFY cmakeconfig.h.in
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)
set(CMAKE_REQUIRED_INCLUDES)
set(CMAKE_REQUIRED_LIBRARIES)
if(NOT HAVE_HEIMDAL_KERBEROS)

View File

@ -88,6 +88,9 @@
/* Define to 1 if you have the `krb5_pac_verify' function. */
#cmakedefine HAVE_KRB5_PAC_VERIFY 1
/* 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 `inflatePrime' function. */
#cmakedefine HAVE_INFLATEPRIME 1

View File

@ -17,15 +17,20 @@ IMPORTS
PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM
PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE {
pa-type [0] Int32,
pa-type [0] PADATA-TYPE, -- use k5.asn Int32,
-- same as padata-type.
pa-hint [1] OCTET STRING OPTIONAL,
pa-value [2] OCTET STRING OPTIONAL,
...
}
KrbFastArmorTypes ::= INTEGER {
fX-FAST-reserved(0),
fX-FAST-ARMOR-AP-REQUEST(1) -- [RFC6113]
}
KrbFastArmor ::= SEQUENCE {
armor-type [0] Int32,
armor-type [0] KrbFastArmorTypes,
-- Type of the armor.
armor-value [1] OCTET STRING,
-- Value of the armor.
@ -37,6 +42,12 @@ PA-FX-FAST-REQUEST ::= CHOICE {
...
}
EncryptedKrbFastReq ::= SEQUENCE {
etype [0] ENCTYPE -- EncryptionType --,
kvno [1] UInt32 OPTIONAL,
cipher [2] OCTET STRING -- ciphertext
}
KrbFastArmoredReq ::= SEQUENCE {
armor [0] KrbFastArmor OPTIONAL,
-- Contains the armor that identifies the armor key.
@ -51,7 +62,7 @@ KrbFastArmoredReq ::= SEQUENCE {
-- type is the required checksum type for the enctype of
-- the armor key, and the key usage number is
-- KEY_USAGE_FAST_REQ_CHKSUM.
enc-fast-req [2] EncryptedData, -- KrbFastReq --
enc-fast-req [2] EncryptedKrbFastReq, -- KrbFastReq --
-- The encryption key is the armor key, and the key usage
-- number is KEY_USAGE_FAST_ENC.
...
@ -70,18 +81,25 @@ KrbFastReq ::= SEQUENCE {
...
}
FastOptions ::= KerberosFlags
-- reserved(0),
-- hide-client-names(1),
-- kdc-follow-referrals(16)
FastOptions ::= BIT STRING {
reserved(0),
hide-client-names(1),
kdc-follow-referrals(16)
} (SIZE (32..MAX)) -- KerberosFlags
PA-FX-FAST-REPLY ::= CHOICE {
armored-data [0] KrbFastArmoredRep,
...
}
EncryptedKrbFastResponse ::= SEQUENCE {
etype [0] ENCTYPE -- EncryptionType --,
kvno [1] UInt32 OPTIONAL,
cipher [2] OCTET STRING -- ciphertext
}
KrbFastArmoredRep ::= SEQUENCE {
enc-fast-rep [0] EncryptedData, -- KrbFastResponse --
enc-fast-rep [0] EncryptedKrbFastResponse, -- KrbFastResponse --
-- The encryption key is the armor key in the request, and
-- the key usage number is KEY_USAGE_FAST_REP.
...
@ -117,8 +135,13 @@ KrbFastFinished ::= SEQUENCE {
...
}
EncryptedChallenge ::= EncryptedData
EncryptedChallenge ::= SEQUENCE {
etype [0] ENCTYPE -- EncryptionType --,
kvno [1] UInt32 OPTIONAL,
cipher [2] OCTET STRING -- ciphertext
}
-- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key
-- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the
-- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC.
END

View File

@ -19,6 +19,9 @@ PA-ENC-TIMESTAMP/cipher pA-ENC-TIMESTAMP_cipher
EncryptedAPREPData/cipher encryptedAPREPData_cipher
EncryptedKrbPrivData/cipher encryptedKrbPrivData_cipher
EncryptedKrbCredData/cipher encryptedKrbCredData_cipher
EncryptedKrbFastReq/cipher encryptedKrbFastReq_cipher
EncryptedKrbFastResponse/cipher encryptedKrbFastResponse_cipher
EncryptedChallenge/cipher encryptedChallenge_cipher
EncAPRepPart/_untag/subkey encAPRepPart_subkey
EncTicketPart/_untag/key encTicketPart_key
EncKDCRepPart/key encKDCRepPart_key
@ -31,6 +34,8 @@ Ticket/_untag/enc-part ticket_enc_part
ETYPE-INFO-ENTRY/salt info_salt
ETYPE-INFO2-ENTRY/salt info2_salt
AP-REQ/_untag/authenticator authenticator_enc_part
PA-FX-FAST-REQUEST/armored-data armored_data_request
PA-FX-FAST-REPLY/armored-data armored_data_reply
#.OMIT_ASSIGNMENT
AD-AND-OR
@ -38,12 +43,15 @@ AD-KDCIssued
AD-LoginAlias
AD-MANDATORY-FOR-KDC
ChangePasswdDataMS
EncryptedData
EtypeList
KerberosFlags
KRB5SignedPath
KRB5SignedPathData
KRB5SignedPathPrincipals
Krb5int32
Krb5uint32
PA-AUTHENTICATION-SET
PA-ClientCanonicalized
PA-ClientCanonicalizedNames
PA-ENC-TS-ENC
@ -60,11 +68,6 @@ Principal
PROV-SRV-LOCATION
SAMFlags
TYPED-DATA
KrbFastReq
KrbFastResponse
KrbFastFinished
FastOptions
KerberosFlags
#.NO_EMIT ONLY_VALS
Applications
@ -78,6 +81,7 @@ Applications TYPE_PREFIX
#.MAKE_ENUM
PADATA-TYPE PROT_PREFIX UPPER_CASE
AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
KrbFastArmorTypes PROT_PREFIX UPPER_CASE
#.FN_BODY MESSAGE-TYPE VAL_PTR = &msgtype
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
@ -137,10 +141,10 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
case KRB5_ET_KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET:
case KRB5_ET_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS:
offset=dissect_ber_octet_string_wcb(FALSE, actx, tree, tvb, offset, hf_kerberos_e_data, dissect_kerberos_SEQUENCE_OF_PA_DATA);
break;
default:
offset=dissect_ber_octet_string(FALSE, actx, tree, tvb, offset, hf_kerberos_e_data, NULL);
break;
}
@ -164,7 +168,9 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
switch(private_data->padata_type){
case KERBEROS_PA_TGS_REQ:
private_data->within_PA_TGS_REQ++;
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_Applications);
private_data->within_PA_TGS_REQ--;
break;
case KERBEROS_PA_PK_AS_REP_19:
private_data->is_win2k_pkinit = TRUE;
@ -210,16 +216,19 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
case KERBEROS_PA_PW_SALT:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_krb5_PW_SALT);
break;
case KERBEROS_PA_AUTHENTICATION_SET:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_PA_AUTHENTICATION_SET);
case KERBEROS_PA_AUTH_SET_SELECTED:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_PA_AUTHENTICATION_SET_ELEM);
break;
case KERBEROS_PA_FX_FAST:
if(private_data->msg_type == KRB5_MSG_AS_REQ || private_data->msg_type == KRB5_MSG_TGS_REQ){
if (kerberos_private_is_kdc_req(private_data)) {
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_PA_FX_FAST_REQUEST);
}else{
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_PA_FX_FAST_REPLY);
}
break;
case KERBEROS_PA_FX_ERROR:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_Applications);
break;
case KERBEROS_PA_ENCRYPTED_CHALLENGE:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, dissect_kerberos_EncryptedChallenge);
break;
@ -234,6 +243,7 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
break;
default:
offset=dissect_ber_octet_string_wcb(FALSE, actx, sub_tree, tvb, offset,hf_index, NULL);
break;
}
#.FN_BODY HostAddress/address
@ -272,6 +282,7 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
default:
proto_tree_add_expert(tree, actx->pinfo, &ei_kerberos_address, tvb, offset, len);
address_str = NULL;
break;
}
/* push it up two levels in the decode pane */
@ -361,6 +372,7 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
break;
default:
offset=dissect_ber_octet_string(FALSE, actx, tree, tvb, offset, hf_index, NULL);
break;
}
#.FN_BODY EncryptionKey/keytype VAL_PTR=&gbl_keytype
@ -463,6 +475,16 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
private_data->save_encryption_key_parent_hf_index = save_encryption_key_parent_hf_index;
private_data->save_encryption_key_fn = saved_encryption_key_fn;
#.FN_BODY KrbFastResponse/strengthen-key
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
gint save_encryption_key_parent_hf_index = private_data->save_encryption_key_parent_hf_index;
kerberos_key_save_fn saved_encryption_key_fn = private_data->save_encryption_key_fn;
private_data->save_encryption_key_parent_hf_index = hf_kerberos_KrbFastResponse;
private_data->save_encryption_key_fn = save_KrbFastResponse_strengthen_key;
%(DEFAULT_BODY)s
private_data->save_encryption_key_parent_hf_index = save_encryption_key_parent_hf_index;
private_data->save_encryption_key_fn = saved_encryption_key_fn;
#.FN_BODY AUTHDATA-TYPE VAL_PTR=&(private_data->ad_type)
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
%(DEFAULT_BODY)s
@ -477,6 +499,9 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
case KERBEROS_AD_IF_RELEVANT:
offset=dissect_ber_octet_string_wcb(implicit_tag, actx, tree, tvb, offset, hf_index, dissect_kerberos_AD_IF_RELEVANT);
break;
case KERBEROS_AD_AUTHENTICATION_STRENGTH:
offset=dissect_ber_octet_string_wcb(implicit_tag, actx, tree, tvb, offset, hf_index, dissect_kerberos_PA_AUTHENTICATION_SET_ELEM);
break;
case KERBEROS_AD_GSS_API_ETYPE_NEGOTIATION:
offset=dissect_ber_octet_string_wcb(implicit_tag, actx, tree, tvb, offset, hf_index, dissect_kerberos_SEQUENCE_OF_ENCTYPE);
break;
@ -491,6 +516,7 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
break;
default:
offset=dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
break;
}
#.FN_BODY S4UUserID/subject-certificate
@ -546,3 +572,44 @@ AUTHDATA-TYPE PROT_PREFIX UPPER_CASE
#.FN_FTR EncKDCRepPart/encrypted-pa-data
private_data->is_enc_padata = FALSE;
#.FN_BODY EncryptedKrbFastReq/cipher
##ifdef HAVE_KERBEROS
offset=dissect_ber_octet_string_wcb(FALSE, actx, tree, tvb, offset, hf_index, dissect_krb5_decrypt_KrbFastReq);
##else
%(DEFAULT_BODY)s
##endif
return offset;
#.FN_BODY EncryptedKrbFastResponse/cipher
##ifdef HAVE_KERBEROS
offset=dissect_ber_octet_string_wcb(FALSE, actx, tree, tvb, offset, hf_index, dissect_krb5_decrypt_KrbFastResponse);
##else
%(DEFAULT_BODY)s
##endif
return offset;
#.FN_BODY EncryptedChallenge/cipher
##ifdef HAVE_KERBEROS
offset=dissect_ber_octet_string_wcb(FALSE, actx, tree, tvb, offset, hf_index, dissect_krb5_decrypt_EncryptedChallenge);
##else
%(DEFAULT_BODY)s
##endif
return offset;
#.FN_BODY KrbFastArmorTypes VAL_PTR=&(private_data->fast_type)
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
%(DEFAULT_BODY)s
#.FN_BODY KrbFastArmor/armor-value
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
switch(private_data->fast_type){
case KERBEROS_FX_FAST_ARMOR_AP_REQUEST:
private_data->fast_armor_within_armor_value++;
offset=dissect_ber_octet_string_wcb(implicit_tag, actx, tree, tvb, offset, hf_index, dissect_kerberos_Applications);
private_data->fast_armor_within_armor_value--;
break;
default:
offset=dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
break;
}

View File

@ -71,6 +71,13 @@
#include "packet-gssapi.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);
@ -114,6 +121,15 @@ typedef struct {
guint learnt_key_ids;
wmem_list_t *decryption_keys;
wmem_list_t *learnt_keys;
guint32 within_PA_TGS_REQ;
enc_key_t *PA_TGS_REQ_key;
enc_key_t *PA_TGS_REQ_subkey;
guint32 fast_type;
guint32 fast_armor_within_armor_value;
enc_key_t *PA_FAST_ARMOR_AP_key;
enc_key_t *PA_FAST_ARMOR_AP_subkey;
enc_key_t *fast_armor_key;
enc_key_t *fast_strengthen_key;
} kerberos_private_data_t;
static dissector_handle_t kerberos_handle_udp;
@ -131,13 +147,15 @@ static int dissect_kerberos_PA_S4U_X509_USER(gboolean implicit_tag _U_, tvbuff_t
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_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_SEQUENCE_OF_ENCTYPE(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_);
/* Desegment Kerberos over TCP messages */
static gboolean krb_desegment = TRUE;
@ -213,6 +231,7 @@ static gint hf_krb_ad_ap_options = -1;
static gint hf_krb_ad_ap_options_cbt = -1;
static gint hf_krb_ad_target_principal = -1;
static gint hf_krb_key_hidden_item = -1;
static gint hf_kerberos_KrbFastResponse = -1;
#ifdef HAVE_KERBEROS
static gint hf_krb_patimestamp = -1;
static gint hf_krb_pausec = -1;
@ -571,14 +590,22 @@ add_encryption_key(packet_info *pinfo,
proto_item *key_hidden_item,
tvbuff_t *key_tvb,
int keytype, int keylength, const char *keyvalue,
const char *origin)
const char *origin,
enc_key_t *src1, enc_key_t *src2)
{
wmem_allocator_t *key_scope = NULL;
enc_key_t *new_key = NULL;
const char *methodl = "learnt";
const char *methodu = "Learnt";
proto_item *item = NULL;
private_data->last_added_key = NULL;
if (src1 != NULL && src2 != NULL) {
methodl = "derived";
methodu = "Derived";
}
if(pinfo->fd->visited){
/*
* We already processed this,
@ -596,7 +623,8 @@ add_encryption_key(packet_info *pinfo,
}
new_key = wmem_new0(key_scope, enc_key_t);
g_snprintf(new_key->key_origin, KRB_MAX_ORIG_LEN, "%s learnt in frame %u",origin,pinfo->num);
g_snprintf(new_key->key_origin, KRB_MAX_ORIG_LEN, "%s %s in frame %u",
methodl, origin, pinfo->num);
new_key->fd_num = pinfo->num;
new_key->id = ++private_data->learnt_key_ids;
g_snprintf(new_key->id_str, KRB_MAX_ID_STR_LEN, "%d.%u",
@ -604,6 +632,8 @@ add_encryption_key(packet_info *pinfo,
new_key->keytype=keytype;
new_key->keylength=keylength;
memcpy(new_key->keyvalue, keyvalue, MIN(keylength, KRB_MAX_KEY_LENGTH));
new_key->src1 = src1;
new_key->src2 = src2;
if(!pinfo->fd->visited){
/*
@ -617,13 +647,31 @@ add_encryption_key(packet_info *pinfo,
item = proto_tree_add_expert_format(key_tree, pinfo, &ei_kerberos_learnt_keytype,
key_tvb, 0, keylength,
"Learnt %s keytype %d (id=%d.%u) (%02x%02x%02x%02x...)",
origin, keytype, pinfo->num, new_key->id,
"%s %s keytype %d (id=%d.%u) (%02x%02x%02x%02x...)",
methodu, origin, keytype, pinfo->num, new_key->id,
keyvalue[0] & 0xFF, keyvalue[1] & 0xFF,
keyvalue[2] & 0xFF, keyvalue[3] & 0xFF);
if (item != NULL && key_hidden_item != NULL) {
proto_tree_move_item(key_tree, key_hidden_item, item);
}
if (src1 != NULL) {
enc_key_t *sek = src1;
expert_add_info_format(pinfo, item, &ei_kerberos_learnt_keytype,
"SRC1 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
if (src2 != NULL) {
enc_key_t *sek = src2;
expert_add_info_format(pinfo, item, &ei_kerberos_learnt_keytype,
"SRC2 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
kerberos_key_list_append(private_data->learnt_keys, new_key);
private_data->last_added_key = new_key;
@ -650,7 +698,9 @@ save_encryption_key(tvbuff_t *tvb _U_, int offset _U_, int length _U_,
private_data->key.keytype,
private_data->key.keylength,
private_data->key.keyvalue,
origin);
origin,
NULL,
NULL);
}
static void
@ -659,7 +709,25 @@ save_Authenticator_subkey(tvbuff_t *tvb, int offset, int length,
int parent_hf_index,
int hf_index)
{
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
save_encryption_key(tvb, offset, length, actx, tree, parent_hf_index, hf_index);
if (private_data->last_decryption_key == NULL) {
return;
}
if (private_data->last_added_key == NULL) {
return;
}
if (private_data->within_PA_TGS_REQ != 0) {
private_data->PA_TGS_REQ_key = private_data->last_decryption_key;
private_data->PA_TGS_REQ_subkey = private_data->last_added_key;
}
if (private_data->fast_armor_within_armor_value != 0) {
private_data->PA_FAST_ARMOR_AP_key = private_data->last_decryption_key;
private_data->PA_FAST_ARMOR_AP_subkey = private_data->last_added_key;
}
}
static void
@ -698,6 +766,19 @@ save_KrbCredInfo_key(tvbuff_t *tvb, int offset, int length,
save_encryption_key(tvb, offset, length, actx, tree, parent_hf_index, hf_index);
}
static void
save_KrbFastResponse_strengthen_key(tvbuff_t *tvb, int offset, int length,
asn1_ctx_t *actx, proto_tree *tree,
int parent_hf_index,
int hf_index)
{
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
save_encryption_key(tvb, offset, length, actx, tree, parent_hf_index, hf_index);
private_data->fast_strengthen_key = private_data->last_added_key;
}
static void used_encryption_key(proto_tree *tree, packet_info *pinfo,
kerberos_private_data_t *private_data,
enc_key_t *ek, int usage, tvbuff_t *cryptotvb)
@ -712,6 +793,24 @@ static void used_encryption_key(proto_tree *tree, packet_info *pinfo,
ek->keytype, usage, ek->key_origin, ek->id_str, ek->num_same,
ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF,
ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
if (ek->src1 != NULL) {
sek = ek->src1;
expert_add_info_format(pinfo, item, &ei_kerberos_decrypted_keytype,
"SRC1 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
if (ek->src2 != NULL) {
sek = ek->src2;
expert_add_info_format(pinfo, item, &ei_kerberos_decrypted_keytype,
"SRC2 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
sek = ek->same_list;
while (sek != NULL) {
expert_add_info_format(pinfo, item, &ei_kerberos_decrypted_keytype,
@ -765,6 +864,58 @@ static void used_signing_key(proto_tree *tree, packet_info *pinfo,
static krb5_context krb5_ctx;
static void
krb5_fast_key(asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb,
enc_key_t *ek1 _U_, const char *p1 _U_,
enc_key_t *ek2 _U_, const char *p2 _U_,
const char *origin _U_)
{
#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
kerberos_private_data_t *private_data = kerberos_get_private_data(actx);
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(actx->pinfo,
private_data,
tree, NULL, tvb,
k->enctype, k->length,
(const char *)k->contents,
origin,
ek1, ek2);
krb5_free_keyblock(krb5_ctx, k);
#endif
}
USES_APPLE_DEPRECATED_API
void
read_keytab_file(const char *filename)
@ -874,6 +1025,12 @@ decrypt_krb5_with_cb_try_key(gpointer __key _U_, gpointer value, gpointer userda
enc_key_t *ek = (enc_key_t *)value;
krb5_error_code ret;
krb5_keytab_entry key;
#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
enc_key_t *ak = state->private_data->fast_armor_key;
enc_key_t *sk = state->private_data->fast_strengthen_key;
gboolean try_with_armor_key = FALSE;
gboolean try_with_strengthen_key = FALSE;
#endif
if (state->ek != NULL) {
/*
@ -882,6 +1039,173 @@ decrypt_krb5_with_cb_try_key(gpointer __key _U_, gpointer value, gpointer userda
return;
}
#ifdef HAVE_KRB5_C_FX_CF2_SIMPLE
if (ak != NULL && ak != ek && ak->keytype == state->keytype && ek->fd_num == -1) {
switch (state->usage) {
case KEY_USAGE_ENC_CHALLENGE_CLIENT:
case KEY_USAGE_ENC_CHALLENGE_KDC:
if (ek->fd_num == -1) {
/* Challenges are based on a long term key */
try_with_armor_key = TRUE;
}
break;
}
/*
* If we already have a strengthen_key
* we don't need to try with the armor key
* again
*/
if (sk != NULL) {
try_with_armor_key = FALSE;
}
}
if (sk != NULL && sk != ek && sk->keytype == state->keytype && sk->keytype == ek->keytype) {
switch (state->usage) {
case 3:
if (ek->fd_num == -1) {
/* AS-REP is based on a long term key */
try_with_strengthen_key = TRUE;
}
break;
case 8:
case 9:
if (ek->fd_num != -1) {
/* TGS-REP is not based on a long term key */
try_with_strengthen_key = TRUE;
}
break;
}
}
if (try_with_armor_key) {
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;
switch (state->usage) {
case KEY_USAGE_ENC_CHALLENGE_CLIENT:
p1 = "clientchallengearmor";
break;
case KEY_USAGE_ENC_CHALLENGE_KDC:
p1 = "kdcchallengearmor";
break;
default:
/*
* Should never be called!
*/
/*
* try the next one...
*/
return;
}
ret = krb5_c_fx_cf2_simple(krb5_ctx,
&k1, p1,
&k2, "challengelongterm",
&k);
if (ret != 0) {
/*
* try the next one...
*/
return;
}
ret = state->decrypt_cb_fn(k,
state->usage,
state->decrypt_cb_data);
if (ret == 0) {
add_encryption_key(state->pinfo,
state->private_data,
state->tree,
NULL,
state->cryptotvb,
k->enctype, k->length,
(const char *)k->contents,
p1,
ak, ek);
krb5_free_keyblock(krb5_ctx, k);
/*
* remember the key and stop traversing
*/
state->ek = state->private_data->last_added_key;
return;
}
krb5_free_keyblock(krb5_ctx, k);
/*
* don't stop traversing...
* try the next one...
*/
return;
}
if (try_with_strengthen_key) {
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) {
/*
* try the next one...
*/
return;
}
ret = state->decrypt_cb_fn(k,
state->usage,
state->decrypt_cb_data);
if (ret == 0) {
add_encryption_key(state->pinfo,
state->private_data,
state->tree,
NULL,
state->cryptotvb,
k->enctype, k->length,
(const char *)k->contents,
"strengthen-reply-key",
sk, ek);
krb5_free_keyblock(krb5_ctx, k);
/*
* remember the key and stop traversing
*/
state->ek = state->private_data->last_added_key;
return;
}
krb5_free_keyblock(krb5_ctx, k);
/*
* don't stop traversing...
* try the next one...
*/
return;
}
#endif
/* shortcircuit and bail out if enctypes are not matching */
if ((state->keytype != -1) && (ek->keytype != state->keytype)) {
/*
@ -1407,6 +1731,15 @@ verify_krb5_pac(proto_tree *tree _U_, asn1_ctx_t *actx, tvbuff_t *pactvb)
static krb5_context krb5_ctx;
USES_APPLE_DEPRECATED_API
static void
krb5_fast_key(asn1_ctx_t *actx, proto_tree *tree, tvbuff_t *tvb,
enc_key_t *ek1 _U_, const char *p1 _U_,
enc_key_t *ek2 _U_, const char *p2 _U_,
const char *origin _U_)
{
/* TODO: use krb5_crypto_fx_cf2() from Heimdal */
}
void
read_keytab_file(const char *filename)
{
@ -1669,6 +2002,13 @@ save_KrbCredInfo_key(tvbuff_t *tvb, int offset, int length,
save_encryption_key(tvb, offset, length, actx, tree, parent_hf_index, hf_index);
}
static void
save_KrbFastResponse_strengthen_key(tvbuff_t *tvb _U_, int offset _U_, int length _U_,
asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)
{
save_encryption_key(tvb, offset, length, actx, tree, hf_index);
}
static void
clear_keytab(void) {
GSList *ske;
@ -2425,6 +2765,141 @@ 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);
private_data->fast_armor_key = NULL;
if (private_data->PA_FAST_ARMOR_AP_subkey != NULL) {
krb5_fast_key(actx, tree, tvb,
private_data->PA_FAST_ARMOR_AP_subkey,
"subkeyarmor",
private_data->PA_FAST_ARMOR_AP_key,
"ticketarmor",
"KrbFastReq_FAST_armorKey");
if (private_data->PA_TGS_REQ_subkey != NULL) {
enc_key_t *explicit_armor_key = private_data->last_added_key;
/*
* See [MS-KILE] 3.3.5.7.4 Compound Identity
*/
krb5_fast_key(actx, tree, tvb,
explicit_armor_key,
"explicitarmor",
private_data->PA_TGS_REQ_subkey,
"tgsarmor",
"KrbFastReq_explicitArmorKey");
}
private_data->fast_armor_key = private_data->last_added_key;
} else if (private_data->PA_TGS_REQ_subkey != NULL) {
krb5_fast_key(actx, tree, tvb,
private_data->PA_TGS_REQ_subkey,
"subkeyarmor",
private_data->PA_TGS_REQ_key,
"ticketarmor",
"KrbFastReq_TGS_armorKey");
private_data->fast_armor_key = private_data->last_added_key;
}
/* RFC6113 :
* KrbFastResponse encrypted with usage
* KEY_USAGE_FAST_ENC 51
*/
plaintext=decrypt_krb5_data_asn1(tree, actx, KEY_USAGE_FAST_ENC,
next_tvb, 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, "Krb5 FastReq");
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_asn1(tree, actx, KEY_USAGE_FAST_REP,
next_tvb, 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, "Krb5 FastRep");
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;
const char *name = NULL;
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 (kerberos_private_is_kdc_req(private_data)) {
usage = KEY_USAGE_ENC_CHALLENGE_CLIENT;
name = "Krb5 CHALLENGE_CLIENT";
} else {
usage = KEY_USAGE_ENC_CHALLENGE_KDC;
name = "Krb5 CHALLENGE_KDC";
}
plaintext=decrypt_krb5_data_asn1(tree, actx, usage, next_tvb, 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, name);
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[] = {
@ -3136,6 +3611,28 @@ kerberos_display_key(gpointer data, gpointer userdata)
ek->id_str, ek->num_same,
ek->keyvalue[0] & 0xFF, ek->keyvalue[1] & 0xFF,
ek->keyvalue[2] & 0xFF, ek->keyvalue[3] & 0xFF);
if (ek->src1 != NULL) {
sek = ek->src1;
expert_add_info_format(state->pinfo,
item,
state->expindex,
"SRC1 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
if (ek->src2 != NULL) {
sek = ek->src2;
expert_add_info_format(state->pinfo,
item,
state->expindex,
"SRC2 %s keytype %d (id=%s same=%u) (%02x%02x%02x%02x...)",
sek->key_origin, sek->keytype,
sek->id_str, sek->num_same,
sek->keyvalue[0] & 0xFF, sek->keyvalue[1] & 0xFF,
sek->keyvalue[2] & 0xFF, sek->keyvalue[3] & 0xFF);
}
sek = ek->same_list;
while (sek != NULL) {
expert_add_info_format(state->pinfo,
@ -3599,6 +4096,9 @@ void proto_register_kerberos(void) {
{ &hf_krb_key_hidden_item,
{ "KeyHiddenItem", "krb5.key_hidden_item",
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_kerberos_KrbFastResponse,
{ "KrbFastResponse", "kerberos.KrbFastResponse_element",
FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
#ifdef HAVE_KERBEROS
{ &hf_krb_patimestamp,
{ "patimestamp", "kerberos.patimestamp",

View File

@ -80,6 +80,8 @@ typedef struct _enc_key_t {
char id_str[KRB_MAX_ID_STR_LEN+1];
struct _enc_key_t *same_list;
guint num_same;
struct _enc_key_t *src1;
struct _enc_key_t *src2;
} enc_key_t;
extern enc_key_t *enc_key_list;
extern wmem_map_t *kerberos_longterm_keys;

File diff suppressed because it is too large Load Diff

View File

@ -88,6 +88,8 @@ typedef struct _enc_key_t {
char id_str[KRB_MAX_ID_STR_LEN+1];
struct _enc_key_t *same_list;
guint num_same;
struct _enc_key_t *src1;
struct _enc_key_t *src2;
} enc_key_t;
extern enc_key_t *enc_key_list;
extern wmem_map_t *kerberos_longterm_keys;
@ -141,7 +143,7 @@ extern gboolean krb_decrypt;
int dissect_kerberos_ChangePasswdData(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_);
/*--- End of included file: packet-kerberos-exp.h ---*/
#line 111 "./asn1/kerberos/packet-kerberos-template.h"
#line 113 "./asn1/kerberos/packet-kerberos-template.h"
#ifdef __cplusplus
}