forked from osmocom/wireshark
c50091ed92
to it (in the *_OR_DIE macros). svn path=/trunk/; revision=2390
954 lines
29 KiB
C
954 lines
29 KiB
C
/* packet-kerberos.c
|
|
* Routines for Kerberos
|
|
* Wes Hardaker (c) 2000
|
|
* wjhardaker@ucdavis.edu
|
|
*
|
|
* $Id: packet-kerberos.c,v 1.4 2000/09/06 19:05:41 gram Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@zing.org>
|
|
* Copyright 1998 Didier Jorand
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
|
|
#include "packet.h"
|
|
|
|
#include "asn1.h"
|
|
|
|
#include "packet-kerberos.h"
|
|
|
|
#define UDP_PORT_KERBEROS 88
|
|
#define TCP_PORT_KERBEROS 88
|
|
|
|
static gint ett_kerberos = -1;
|
|
static gint ett_preauth = -1;
|
|
static gint ett_addresses = -1;
|
|
static gint ett_request = -1;
|
|
static gint ett_princ = -1;
|
|
static gint ett_ticket = -1;
|
|
static gint ett_encrypted = -1;
|
|
static gint ett_etype = -1;
|
|
static gint proto_kerberos = -1;
|
|
|
|
#define KRB5_MSG_AS_REQ 0x0a
|
|
#define KRB5_MSG_AS_RESP 0x0b
|
|
#define KRB5_MSG_TGS_REQ 0x0c
|
|
#define KRB5_MSG_TGS_RESP 0x0d
|
|
|
|
#define KRB5_KDC_REQ_PVNO 0x01
|
|
#define KRB5_KDC_REQ_MSG_TYPE 0x02
|
|
#define KRB5_KDC_REQ_PADATA 0x03
|
|
#define KRB5_KDC_REQ_REQBODY 0x04
|
|
|
|
#define KRB5_KDC_RESP_PVNO 0x00
|
|
#define KRB5_KDC_RESP_MSG_TYPE 0x01
|
|
#define KRB5_KDC_RESP_PADATA 0x02
|
|
#define KRB5_KDC_RESP_CREALM 0x03
|
|
#define KRB5_KDC_RESP_CNAME 0x04
|
|
#define KRB5_KDC_RESP_TICKET 0x05
|
|
#define KRB5_KDC_RESP_ENC_PART 0x06
|
|
|
|
#define KRB5_BODY_KDC_OPTIONS 0x00
|
|
#define KRB5_BODY_CNAME 0x01
|
|
#define KRB5_BODY_REALM 0x02
|
|
#define KRB5_BODY_SNAME 0x03
|
|
#define KRB5_BODY_FROM 0x04
|
|
#define KRB5_BODY_TILL 0x05
|
|
#define KRB5_BODY_RTIME 0x06
|
|
#define KRB5_BODY_NONCE 0x07
|
|
#define KRB5_BODY_ETYPE 0x08
|
|
#define KRB5_BODY_ADDRESSES 0x09
|
|
#define KRB5_BODY_ENC_AUTHORIZATION_DATA 0x0a
|
|
#define KRB5_BODY_ADDITIONAL_TICKETS 0x0b
|
|
|
|
#define KRB5_ADDR_IPv4 0x02
|
|
#define KRB5_ADDR_CHAOS 0x05
|
|
#define KRB5_ADDR_XEROX 0x06
|
|
#define KRB5_ADDR_ISO 0x07
|
|
#define KRB5_ADDR_DECNET 0x0c
|
|
#define KRB5_ADDR_APPLETALK 0x10
|
|
|
|
#define KRB5_ETYPE_NULL 0
|
|
#define KRB5_ETYPE_DES_CBC_CRC 1
|
|
#define KRB5_ETYPE_DES_CBC_MD4 2
|
|
#define KRB5_ETYPE_DES_CBC_MD5 3
|
|
|
|
#define KRB5_PA_TGS_REQ 0x01
|
|
#define KRB5_PA_ENC_TIMESTAMP 0x02
|
|
#define KRB5_PA_PW_SALT 0x03
|
|
|
|
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" },
|
|
};
|
|
|
|
static const value_string krb5_encryption_types[] = {
|
|
{ KRB5_ETYPE_NULL , "NULL" },
|
|
{ KRB5_ETYPE_DES_CBC_CRC , "des-cbc-crc" },
|
|
{ KRB5_ETYPE_DES_CBC_MD4 , "des-cbc-md4" },
|
|
{ KRB5_ETYPE_DES_CBC_MD5 , "des-cbc-md5" },
|
|
};
|
|
|
|
static const value_string krb5_address_types[] = {
|
|
{ KRB5_ADDR_IPv4, "IPv4"},
|
|
{ KRB5_ADDR_CHAOS, "CHAOS"},
|
|
{ KRB5_ADDR_XEROX, "XEROX"},
|
|
{ KRB5_ADDR_ISO, "ISO"},
|
|
{ KRB5_ADDR_DECNET, "DECNET"},
|
|
{ KRB5_ADDR_APPLETALK, "APPLETALK"}
|
|
};
|
|
|
|
static const value_string krb5_msg_types[] = {
|
|
{ KRB5_MSG_TGS_REQ, "TGS-REQ" },
|
|
{ KRB5_MSG_TGS_RESP, "TGS-RESP" },
|
|
{ KRB5_MSG_AS_REQ, "AS-REQ" },
|
|
{ KRB5_MSG_AS_RESP, "AS-RESP" }
|
|
};
|
|
|
|
const char *
|
|
to_error_str(int ret) {
|
|
switch (ret) {
|
|
|
|
case ASN1_ERR_EMPTY:
|
|
return("Ran out of data");
|
|
|
|
case ASN1_ERR_EOC_MISMATCH:
|
|
return("EOC mismatch");
|
|
|
|
case ASN1_ERR_WRONG_TYPE:
|
|
return("Wrong type for that item");
|
|
|
|
case ASN1_ERR_LENGTH_NOT_DEFINITE:
|
|
return("Length was indefinite");
|
|
|
|
case ASN1_ERR_LENGTH_MISMATCH:
|
|
return("Length mismatch");
|
|
|
|
case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
|
|
return("Wrong length for that item's type");
|
|
|
|
}
|
|
return("Unknown error");
|
|
}
|
|
|
|
void
|
|
krb_proto_tree_add_time(proto_tree *tree, int offset, int str_len,
|
|
char *name, guchar *str) {
|
|
if (tree)
|
|
proto_tree_add_text(tree, NullTVB, offset, str_len,
|
|
"%s: %.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
|
|
name, str, str+4, str+6,
|
|
str+8, str+10, str+12,
|
|
str+14);
|
|
}
|
|
|
|
|
|
/*
|
|
* You must be kidding. I'm going to actually use a macro to do something?
|
|
* bad me. Bad me.
|
|
*/
|
|
|
|
#define KRB_HEAD_DECODE_OR_DIE(token) \
|
|
start = asn1p->pointer; \
|
|
ret = asn1_header_decode (asn1p, &cls, &con, &tag, &def, &item_len); \
|
|
if (ret != ASN1_ERR_NOERROR && ret != ASN1_ERR_EMPTY) {\
|
|
if (check_col(fd, COL_INFO)) \
|
|
col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
|
|
token, to_error_str(ret)); \
|
|
return; \
|
|
} \
|
|
if (!def) {\
|
|
if (check_col(fd, COL_INFO)) \
|
|
col_add_fstr(fd, COL_INFO, "not definite: %s", token); \
|
|
fprintf(stderr,"not definite: %s\n", token); \
|
|
return; \
|
|
} \
|
|
offset += (asn1p->pointer - start);
|
|
|
|
|
|
#define KRB_DECODE_OR_DIE(token, fn, val) \
|
|
ret = fn (asn1p, &val, &length); \
|
|
if (ret != ASN1_ERR_NOERROR) { \
|
|
if (check_col(fd, COL_INFO)) \
|
|
col_add_fstr(fd, COL_INFO, "ERROR: Problem at %s: %s", \
|
|
token, to_error_str(ret)); \
|
|
return; \
|
|
} \
|
|
|
|
/* dissect_type_value_pair decodes (roughly) this:
|
|
|
|
SEQUENCE {
|
|
INTEGER,
|
|
OCTET STRING
|
|
}
|
|
|
|
which is all over the place in krb5 */
|
|
|
|
void
|
|
dissect_type_value_pair(ASN1_SCK *asn1p, int *inoff,
|
|
int *type, int *type_len, int *type_off,
|
|
guchar **val, int *val_len, int *val_off) {
|
|
int offset = *inoff;
|
|
guint cls, con, tag;
|
|
gboolean def;
|
|
const guchar *start;
|
|
guint tmp_len;
|
|
int ret;
|
|
|
|
/* SEQUENCE */
|
|
start = asn1p->pointer;
|
|
asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
|
|
offset += (asn1p->pointer - start);
|
|
|
|
/* INT */
|
|
/* wrapper */
|
|
start = asn1p->pointer;
|
|
asn1_header_decode (asn1p, &cls, &con, &tag, &def, &tmp_len);
|
|
offset += (asn1p->pointer - start);
|
|
|
|
if (type_off)
|
|
*type_off = offset;
|
|
|
|
/* value */
|
|
ret = asn1_int32_decode(asn1p, type, type_len);
|
|
if (ret != ASN1_ERR_NOERROR) {
|
|
fprintf(stderr,"die: type_value_pair: type, %s\n", to_error_str(ret));
|
|
return;
|
|
}
|
|
offset += tmp_len;
|
|
|
|
/* OCTET STRING (or generic data) */
|
|
/* wrapper */
|
|
start = asn1p->pointer;
|
|
asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
|
|
asn1_header_decode (asn1p, &cls, &con, &tag, &def, val_len);
|
|
offset += asn1p->pointer - start;
|
|
|
|
if (val_off)
|
|
*val_off = offset;
|
|
|
|
/* value */
|
|
asn1_octet_string_value_decode (asn1p, *val_len, val);
|
|
|
|
*inoff = offset + *val_len;
|
|
}
|
|
|
|
|
|
void
|
|
dissect_kerberos(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
|
|
{
|
|
proto_tree *kerberos_tree = NULL;
|
|
proto_tree *etype_tree = NULL;
|
|
proto_tree *preauth_tree = NULL;
|
|
proto_tree *request_tree = NULL;
|
|
ASN1_SCK asn1, *asn1p = &asn1;
|
|
proto_item *item = NULL;
|
|
|
|
guint length;
|
|
guint cls, con, tag;
|
|
gboolean def;
|
|
guint item_len, total_len;
|
|
const guchar *start;
|
|
|
|
int ret;
|
|
|
|
guint protocol_message_type;
|
|
|
|
gint32 version;
|
|
gint32 msg_type;
|
|
gint32 preauth_type;
|
|
gint32 tmp_int;
|
|
|
|
/* simple holders */
|
|
int str_len;
|
|
guchar *str;
|
|
int tmp_pos1, tmp_pos2;
|
|
|
|
OLD_CHECK_DISPLAY_AS_DATA(proto_kerberos, pd, offset, fd, tree);
|
|
|
|
if (check_col(fd, COL_PROTOCOL))
|
|
col_add_str(fd, COL_PROTOCOL, "KRB5");
|
|
|
|
if (tree) {
|
|
item = proto_tree_add_item(tree, proto_kerberos, NullTVB, offset,
|
|
END_OF_FRAME, FALSE);
|
|
kerberos_tree = proto_item_add_subtree(item, ett_kerberos);
|
|
}
|
|
|
|
asn1_open(&asn1, &pd[offset], END_OF_FRAME);
|
|
|
|
/* top header */
|
|
KRB_HEAD_DECODE_OR_DIE("top");
|
|
protocol_message_type = tag;
|
|
|
|
/* second header */
|
|
KRB_HEAD_DECODE_OR_DIE("top2");
|
|
|
|
/* version number */
|
|
KRB_HEAD_DECODE_OR_DIE("version-wrap");
|
|
KRB_DECODE_OR_DIE("version", asn1_int32_decode, version);
|
|
|
|
if (kerberos_tree) {
|
|
proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
|
|
"Version: %d",
|
|
version);
|
|
}
|
|
offset += length;
|
|
|
|
/* message type */
|
|
KRB_HEAD_DECODE_OR_DIE("message-type-wrap");
|
|
KRB_DECODE_OR_DIE("message-type", asn1_int32_decode, msg_type);
|
|
|
|
if (kerberos_tree) {
|
|
proto_tree_add_text(kerberos_tree, NullTVB, offset, length,
|
|
"MSG Type: %s",
|
|
val_to_str(msg_type, krb5_msg_types,
|
|
"Unknown msg type %#x"));
|
|
}
|
|
offset += length;
|
|
|
|
if (check_col(fd, COL_INFO))
|
|
col_add_str(fd, COL_INFO, val_to_str(msg_type, krb5_msg_types,
|
|
"Unknown msg type %#x"));
|
|
|
|
/* is preauthentication present? */
|
|
KRB_HEAD_DECODE_OR_DIE("padata-or-body");
|
|
if (((protocol_message_type == KRB5_MSG_AS_REQ ||
|
|
protocol_message_type == KRB5_MSG_TGS_REQ) &&
|
|
tag == KRB5_KDC_REQ_PADATA) ||
|
|
((protocol_message_type == KRB5_MSG_AS_RESP ||
|
|
protocol_message_type == KRB5_MSG_TGS_RESP) &&
|
|
tag == KRB5_KDC_RESP_PADATA)) {
|
|
/* pre-authentication supplied */
|
|
|
|
if (tree) {
|
|
item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
|
|
item_len, "Pre-Authentication");
|
|
preauth_tree = proto_item_add_subtree(item, ett_preauth);
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("sequence of pa-data");
|
|
start = asn1p->pointer + item_len;
|
|
|
|
while(start > asn1p->pointer) {
|
|
dissect_type_value_pair(asn1p, &offset,
|
|
&preauth_type, &item_len, &tmp_pos1,
|
|
&str, &str_len, &tmp_pos2);
|
|
|
|
if (preauth_tree) {
|
|
proto_tree_add_text(preauth_tree, NullTVB, tmp_pos1,
|
|
item_len, "Type: %s",
|
|
val_to_str(preauth_type,
|
|
krb5_preauthentication_types,
|
|
"Unknown preauth type %#x"));
|
|
proto_tree_add_text(preauth_tree, NullTVB, tmp_pos2,
|
|
str_len, "Value: %s",
|
|
bytes_to_str(str, str_len));
|
|
}
|
|
}
|
|
KRB_HEAD_DECODE_OR_DIE("message-body");
|
|
}
|
|
|
|
if (protocol_message_type == KRB5_MSG_AS_REQ ||
|
|
protocol_message_type == KRB5_MSG_TGS_REQ) {
|
|
|
|
/* request body */
|
|
KRB_HEAD_DECODE_OR_DIE("body-sequence");
|
|
if (tree) {
|
|
item = proto_tree_add_text(kerberos_tree, NullTVB, offset,
|
|
item_len, "Request");
|
|
request_tree = proto_item_add_subtree(item, ett_request);
|
|
}
|
|
|
|
/* kdc options */
|
|
KRB_HEAD_DECODE_OR_DIE("kdc options");
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("kdc options:bits");
|
|
|
|
if (request_tree) {
|
|
proto_tree_add_text(request_tree, NullTVB, offset, item_len,
|
|
"Options: %s",
|
|
bytes_to_str(asn1.pointer, item_len));
|
|
}
|
|
offset += item_len;
|
|
asn1.pointer += item_len;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("Principal Name");
|
|
|
|
if (tag == KRB5_BODY_CNAME) {
|
|
dissect_PrincipalName("Client Name", asn1p, fd, request_tree,
|
|
&offset);
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
}
|
|
|
|
if (tag == KRB5_BODY_REALM) {
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
if (request_tree) {
|
|
proto_tree_add_text(request_tree, NullTVB, offset, str_len,
|
|
"Realm: %.*s", str_len, str);
|
|
}
|
|
offset += str_len;
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (tag == KRB5_BODY_SNAME) {
|
|
dissect_PrincipalName("Server Name", asn1p, fd, request_tree, &offset);
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
}
|
|
|
|
if (tag == KRB5_BODY_FROM) {
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
krb_proto_tree_add_time(request_tree, offset, str_len,
|
|
"Start Time", str);
|
|
offset += str_len;
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
}
|
|
|
|
if (tag == KRB5_BODY_TILL) {
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
krb_proto_tree_add_time(request_tree, offset, str_len,
|
|
"End Time", str);
|
|
offset += str_len;
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (tag == KRB5_BODY_RTIME) {
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
krb_proto_tree_add_time(request_tree, offset, str_len,
|
|
"Renewable Until", str);
|
|
offset += str_len;
|
|
KRB_HEAD_DECODE_OR_DIE("realm name");
|
|
}
|
|
|
|
if (tag == KRB5_BODY_NONCE) {
|
|
ret = asn1_int32_decode(asn1p, &tmp_int, &length);
|
|
if (ret != ASN1_ERR_NOERROR) {
|
|
fprintf(stderr,"die: nonce, %s\n", to_error_str(ret));
|
|
return;
|
|
}
|
|
if (request_tree) {
|
|
proto_tree_add_text(request_tree, NullTVB, offset, length,
|
|
"Random Number: %d",
|
|
tmp_int);
|
|
}
|
|
offset += length;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("encryption type spot");
|
|
if (tag == KRB5_BODY_ETYPE) {
|
|
KRB_HEAD_DECODE_OR_DIE("encryption type list");
|
|
if (kerberos_tree) {
|
|
item = proto_tree_add_text(request_tree, NullTVB, offset,
|
|
item_len, "Encryption Types");
|
|
etype_tree = proto_item_add_subtree(item, ett_etype);
|
|
}
|
|
total_len = item_len;
|
|
while(total_len > 0) {
|
|
ret = asn1_int32_decode(asn1p, &tmp_int, &length);
|
|
if (ret != ASN1_ERR_NOERROR) {
|
|
fprintf(stderr,"die: etype, %s\n", to_error_str(ret));
|
|
return;
|
|
}
|
|
if (etype_tree) {
|
|
proto_tree_add_text(etype_tree, NullTVB, offset, length,
|
|
"Type: %s",
|
|
val_to_str(tmp_int,
|
|
krb5_encryption_types,
|
|
"Unknown encryption type %#x"));
|
|
}
|
|
offset += length;
|
|
total_len -= length;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("addresses");
|
|
if (tag == KRB5_BODY_ADDRESSES) {
|
|
/* pre-authentication supplied */
|
|
|
|
dissect_Addresses("Addresses", asn1p, fd, kerberos_tree, &offset);
|
|
KRB_HEAD_DECODE_OR_DIE("auth-data");
|
|
}
|
|
} else if (protocol_message_type == KRB5_MSG_AS_RESP ||
|
|
protocol_message_type == KRB5_MSG_TGS_RESP) {
|
|
if (tag == KRB5_KDC_RESP_CREALM) {
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
if (kerberos_tree) {
|
|
proto_tree_add_text(kerberos_tree, NullTVB, offset, str_len,
|
|
"Realm: %.*s", str_len, str);
|
|
}
|
|
offset += str_len;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("cname");
|
|
if (tag == KRB5_KDC_RESP_CNAME) {
|
|
dissect_PrincipalName("Client Name", asn1p, fd, kerberos_tree,
|
|
&offset);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("ticket");
|
|
if (tag == KRB5_KDC_RESP_TICKET) {
|
|
dissect_ticket("ticket", asn1p, fd, kerberos_tree, &offset);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("enc-msg-part");
|
|
if (tag == KRB5_KDC_RESP_TICKET) {
|
|
dissect_EncryptedData("Encrypted Payload", asn1p, fd, kerberos_tree,
|
|
&offset);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
dissect_GeneralString(ASN1_SCK *asn1p, guchar **where,
|
|
guint *item_len, guint *pkt_len)
|
|
{
|
|
guint cls, con, tag;
|
|
gboolean def;
|
|
const guchar *start = asn1p->pointer;
|
|
|
|
asn1_header_decode (asn1p, &cls, &con, &tag, &def, item_len);
|
|
asn1_octet_string_value_decode (asn1p, *item_len, where);
|
|
*pkt_len = asn1p->pointer - start;
|
|
}
|
|
|
|
void
|
|
dissect_PrincipalName(char *title, ASN1_SCK *asn1p, frame_data *fd,
|
|
proto_tree *tree, int *inoff) {
|
|
proto_tree *princ_tree = NULL;
|
|
int offset = 0;
|
|
|
|
gint32 princ_type;
|
|
|
|
const guchar *start;
|
|
guint cls, con, tag;
|
|
guint item_len, total_len, type_len;
|
|
int ret;
|
|
|
|
proto_item *item = NULL;
|
|
guint length;
|
|
gboolean def;
|
|
|
|
int type_offset;
|
|
|
|
guchar *name;
|
|
guint name_len;
|
|
|
|
if (inoff)
|
|
offset = *inoff;
|
|
|
|
/* principal name */
|
|
KRB_HEAD_DECODE_OR_DIE("principal section");
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("principal type");
|
|
KRB_DECODE_OR_DIE("princ-type", asn1_int32_decode, princ_type);
|
|
type_offset = offset;
|
|
type_len = item_len;
|
|
offset += length;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("cname header");
|
|
total_len = item_len;
|
|
|
|
dissect_GeneralString(asn1p, &name, &name_len, &item_len);
|
|
offset += item_len - name_len;
|
|
|
|
if (tree) {
|
|
item = proto_tree_add_text(tree, NullTVB, *inoff, total_len,
|
|
"%s: %.*s", title, (int) name_len, name);
|
|
princ_tree = proto_item_add_subtree(item, ett_princ);
|
|
|
|
proto_tree_add_text(princ_tree, NullTVB, type_offset, type_len,
|
|
"Type: %d", princ_type);
|
|
proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
|
|
"Name: %.*s", (int) name_len, name);
|
|
}
|
|
|
|
total_len -= item_len;
|
|
offset += name_len;
|
|
|
|
while(total_len > 0) {
|
|
dissect_GeneralString(asn1p, &name, &name_len, &item_len);
|
|
offset += item_len - name_len;
|
|
if (princ_tree) {
|
|
proto_tree_add_text(princ_tree, NullTVB, offset, name_len,
|
|
"Name: %.*s", (int) name_len, name);
|
|
}
|
|
total_len -= item_len;
|
|
offset += name_len;
|
|
}
|
|
if (inoff)
|
|
*inoff = offset;
|
|
}
|
|
|
|
void
|
|
dissect_Addresses(char *title, ASN1_SCK *asn1p, frame_data *fd,
|
|
proto_tree *tree, int *inoff) {
|
|
proto_tree *address_tree = NULL;
|
|
int offset = 0;
|
|
|
|
const guchar *start;
|
|
guint cls, con, tag;
|
|
guint item_len;
|
|
int ret;
|
|
|
|
proto_item *item = NULL;
|
|
gboolean def;
|
|
|
|
int tmp_pos1, tmp_pos2;
|
|
gint32 address_type;
|
|
|
|
int str_len;
|
|
guchar *str;
|
|
|
|
if (inoff)
|
|
offset = *inoff;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("sequence of addresses");
|
|
if (tree) {
|
|
item = proto_tree_add_text(tree, NullTVB, offset,
|
|
item_len, "Addresses");
|
|
address_tree = proto_item_add_subtree(item, ett_addresses);
|
|
}
|
|
|
|
start = asn1p->pointer + item_len;
|
|
|
|
while(start > asn1p->pointer) {
|
|
dissect_type_value_pair(asn1p, &offset,
|
|
&address_type, &item_len, &tmp_pos1,
|
|
&str, &str_len, &tmp_pos2);
|
|
|
|
if (address_tree) {
|
|
proto_tree_add_text(address_tree, NullTVB, tmp_pos1,
|
|
item_len, "Type: %s",
|
|
val_to_str(address_type, krb5_address_types,
|
|
"Unknown address type %#x"));
|
|
switch(address_type) {
|
|
case KRB5_ADDR_IPv4:
|
|
proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
|
|
str_len, "Value: %d.%d.%d.%d",
|
|
str[0], str[1], str[2], str[3]);
|
|
break;
|
|
|
|
default:
|
|
proto_tree_add_text(address_tree, NullTVB, tmp_pos2,
|
|
str_len, "Value: %s",
|
|
bytes_to_str(str, str_len));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (inoff)
|
|
*inoff = offset;
|
|
}
|
|
|
|
void
|
|
dissect_EncryptedData(char *title, ASN1_SCK *asn1p, frame_data *fd,
|
|
proto_tree *tree, int *inoff) {
|
|
proto_tree *encr_tree = NULL;
|
|
int offset = 0;
|
|
|
|
const guchar *start;
|
|
guint cls, con, tag;
|
|
guint item_len;
|
|
int ret;
|
|
|
|
proto_item *item = NULL;
|
|
guint length;
|
|
gboolean def;
|
|
int val;
|
|
|
|
guchar *data;
|
|
|
|
if (inoff)
|
|
offset = *inoff;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("encrypted data section");
|
|
|
|
if (tree) {
|
|
item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
|
|
"Encrypted Data: %s", title);
|
|
encr_tree = proto_item_add_subtree(item, ett_princ);
|
|
}
|
|
|
|
/* type */
|
|
KRB_HEAD_DECODE_OR_DIE("encryption type");
|
|
KRB_DECODE_OR_DIE("encr-type", asn1_int32_decode, val);
|
|
|
|
if (encr_tree) {
|
|
proto_tree_add_text(encr_tree, NullTVB, offset, length,
|
|
"Type: %s",
|
|
val_to_str(val, krb5_encryption_types,
|
|
"Unknown encryption type %#x"));
|
|
}
|
|
offset += length;
|
|
|
|
/* kvno */
|
|
KRB_HEAD_DECODE_OR_DIE("kvno-wrap");
|
|
KRB_DECODE_OR_DIE("kvno", asn1_int32_decode, val);
|
|
|
|
if (encr_tree) {
|
|
proto_tree_add_text(encr_tree, NullTVB, offset, length,
|
|
"KVNO: %d", val);
|
|
}
|
|
offset += length;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("cipher-wrap");
|
|
KRB_HEAD_DECODE_OR_DIE("cipher");
|
|
asn1_octet_string_value_decode (asn1p, item_len, &data);
|
|
|
|
if (encr_tree) {
|
|
proto_tree_add_text(encr_tree, NullTVB, offset, length,
|
|
"Cipher: %s", bytes_to_str(data, item_len));
|
|
}
|
|
offset += item_len;
|
|
|
|
if (inoff)
|
|
*inoff = offset;
|
|
}
|
|
|
|
void
|
|
dissect_ticket(char *title, ASN1_SCK *asn1p, frame_data *fd, proto_tree *tree,
|
|
int *inoff) {
|
|
/*
|
|
Ticket ::= [APPLICATION 1] SEQUENCE {
|
|
tkt-vno[0] INTEGER,
|
|
realm[1] Realm,
|
|
sname[2] PrincipalName,
|
|
enc-part[3] EncryptedData
|
|
}
|
|
*/
|
|
proto_tree *ticket_tree = NULL;
|
|
int offset = 0;
|
|
|
|
const guchar *start;
|
|
guint cls, con, tag;
|
|
guint item_len;
|
|
int ret;
|
|
|
|
proto_item *item = NULL;
|
|
guint length;
|
|
gboolean def;
|
|
int val;
|
|
|
|
int str_len;
|
|
guchar *str;
|
|
|
|
if (inoff)
|
|
offset = *inoff;
|
|
|
|
KRB_HEAD_DECODE_OR_DIE("ticket section");
|
|
KRB_HEAD_DECODE_OR_DIE("ticket sequence");
|
|
|
|
if (tree) {
|
|
item = proto_tree_add_text(tree, NullTVB, *inoff, item_len,
|
|
"Ticket");
|
|
ticket_tree = proto_item_add_subtree(item, ett_ticket);
|
|
}
|
|
|
|
/* type */
|
|
KRB_HEAD_DECODE_OR_DIE("ticket type");
|
|
KRB_DECODE_OR_DIE("ticket-type", asn1_int32_decode, val);
|
|
|
|
if (ticket_tree) {
|
|
proto_tree_add_text(ticket_tree, NullTVB, offset, length,
|
|
"Version: %d", val);
|
|
}
|
|
offset += length;
|
|
|
|
/* realm name */
|
|
KRB_HEAD_DECODE_OR_DIE("realm");
|
|
dissect_GeneralString(asn1p, &str, &str_len, &item_len);
|
|
offset += item_len - str_len;
|
|
if (ticket_tree) {
|
|
proto_tree_add_text(ticket_tree, NullTVB, offset, str_len,
|
|
"Realm: %.*s", str_len, str);
|
|
}
|
|
offset += str_len;
|
|
|
|
/* server name (sname) */
|
|
KRB_HEAD_DECODE_OR_DIE("sname");
|
|
dissect_PrincipalName("Service Name", asn1p, fd, ticket_tree, &offset);
|
|
|
|
/* ticket */
|
|
KRB_HEAD_DECODE_OR_DIE("enc-part");
|
|
dissect_EncryptedData("ticket data", asn1p, fd, ticket_tree, &offset);
|
|
|
|
if (inoff)
|
|
*inoff = offset;
|
|
}
|
|
|
|
|
|
void
|
|
proto_register_kerberos(void) {
|
|
/*
|
|
static hf_register_info hf[] = {
|
|
};
|
|
*/
|
|
static gint *ett[] = {
|
|
&ett_kerberos,
|
|
&ett_preauth,
|
|
&ett_request,
|
|
&ett_princ,
|
|
&ett_encrypted,
|
|
&ett_ticket,
|
|
&ett_addresses,
|
|
&ett_etype,
|
|
};
|
|
proto_kerberos = proto_register_protocol("Kerberos", "kerberos");
|
|
/*
|
|
proto_register_field_array(proto_kerberos, hf, array_length(hf));
|
|
*/
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_kerberos(void)
|
|
{
|
|
old_dissector_add("udp.port", UDP_PORT_KERBEROS, dissect_kerberos);
|
|
old_dissector_add("tcp.port", TCP_PORT_KERBEROS, dissect_kerberos);
|
|
}
|
|
|
|
/*
|
|
|
|
MISC definitions from RFC1510:
|
|
|
|
KerberosTime ::= GeneralizedTime
|
|
Realm ::= GeneralString
|
|
PrincipalName ::= SEQUENCE {
|
|
name-type[0] INTEGER,
|
|
name-string[1] SEQUENCE OF GeneralString
|
|
}
|
|
HostAddress ::= SEQUENCE {
|
|
addr-type[0] INTEGER,
|
|
address[1] OCTET STRING
|
|
}
|
|
|
|
HostAddresses ::= SEQUENCE OF SEQUENCE {
|
|
addr-type[0] INTEGER,
|
|
address[1] OCTET STRING
|
|
}
|
|
|
|
AS-REQ ::= [APPLICATION 10] KDC-REQ
|
|
TGS-REQ ::= [APPLICATION 12] KDC-REQ
|
|
|
|
KDC-REQ ::= SEQUENCE {
|
|
pvno[1] INTEGER,
|
|
msg-type[2] INTEGER,
|
|
padata[3] SEQUENCE OF PA-DATA OPTIONAL,
|
|
req-body[4] KDC-REQ-BODY
|
|
}
|
|
|
|
PA-DATA ::= SEQUENCE {
|
|
padata-type[1] INTEGER,
|
|
padata-value[2] OCTET STRING,
|
|
-- might be encoded AP-REQ
|
|
}
|
|
|
|
KDC-REQ-BODY ::= SEQUENCE {
|
|
kdc-options[0] KDCOptions,
|
|
cname[1] PrincipalName OPTIONAL,
|
|
-- Used only in AS-REQ
|
|
realm[2] Realm, -- Server's realm
|
|
-- Also client's in AS-REQ
|
|
sname[3] PrincipalName OPTIONAL,
|
|
from[4] KerberosTime OPTIONAL,
|
|
till[5] KerberosTime,
|
|
rtime[6] KerberosTime OPTIONAL,
|
|
nonce[7] INTEGER,
|
|
etype[8] SEQUENCE OF INTEGER, -- EncryptionType,
|
|
-- in preference order
|
|
addresses[9] HostAddresses OPTIONAL,
|
|
enc-authorization-data[10] EncryptedData OPTIONAL,
|
|
-- Encrypted AuthorizationData encoding
|
|
additional-tickets[11] SEQUENCE OF Ticket OPTIONAL
|
|
}
|
|
|
|
AS-REP ::= [APPLICATION 11] KDC-REP
|
|
TGS-REP ::= [APPLICATION 13] KDC-REP
|
|
|
|
KDC-REP ::= SEQUENCE {
|
|
pvno[0] INTEGER,
|
|
msg-type[1] INTEGER,
|
|
padata[2] SEQUENCE OF PA-DATA OPTIONAL,
|
|
crealm[3] Realm,
|
|
cname[4] PrincipalName,
|
|
ticket[5] Ticket,
|
|
enc-part[6] EncryptedData
|
|
}
|
|
|
|
EncASRepPart ::= [APPLICATION 25[25]] EncKDCRepPart
|
|
EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart
|
|
|
|
EncKDCRepPart ::= SEQUENCE {
|
|
key[0] EncryptionKey,
|
|
last-req[1] LastReq,
|
|
nonce[2] INTEGER,
|
|
key-expiration[3] KerberosTime OPTIONAL,
|
|
flags[4] TicketFlags,
|
|
authtime[5] KerberosTime,
|
|
starttime[6] KerberosTime OPTIONAL,
|
|
endtime[7] KerberosTime,
|
|
renew-till[8] KerberosTime OPTIONAL,
|
|
srealm[9] Realm,
|
|
sname[10] PrincipalName,
|
|
caddr[11] HostAddresses OPTIONAL
|
|
}
|
|
|
|
Ticket ::= [APPLICATION 1] SEQUENCE {
|
|
tkt-vno[0] INTEGER,
|
|
realm[1] Realm,
|
|
sname[2] PrincipalName,
|
|
enc-part[3] EncryptedData
|
|
}
|
|
|
|
|
|
*/
|