wireshark/packet-kerberos.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
}
*/