0% found this document useful (0 votes)
75 views26 pages

Appendix C - Wireshark Code Sample

Uploaded by

john arias
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
75 views26 pages

Appendix C - Wireshark Code Sample

Uploaded by

john arias
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

WSU04: Wireshark Network Forensics

and Security

Appendix C:
Wireshark Code
Wireshark University

SSL Dissector Code


The following code is from the packet-ssl.c which can be found at
[Link]

Note: This is only a portion of the code. See [Link] in the \misc directory on the
Student Supplement DVD.

/* packet-ssl.c
* Routines for ssl dissection
* Copyright (c) 2000-2001, Scott Renfro <scott@[Link]>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@[Link]>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*

References
• See [Link] for SSL 2.0 specs.
• See [Link] SSL 3.0 specs.
• See RFC 2246 for SSL 3.1/TLS 1.0 specs.
• See (among other places) [Link] for PCT
1 draft specs.
• See [Link] for Elliptic
Curve Cryptography cipher suites.
• See [Link] for
Camellia-based cipher suites.

WSU04: Network Forensics and Security – Appendix C Page C-2


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

Notes Regarding Dissection


*
* - Does not support dissection
* of frames that would require state maintained between frames
* (e.g., single ssl records spread across multiple tcp frames)
*
* - Identifies, but does not fully dissect the following messages:
*
* - SSLv3/TLS (These need more state from previous handshake msgs)
* - Server Key Exchange
* - Client Key Exchange
* - Certificate Verify
*
* - SSLv2 (These don't appear in the clear)
* - Error
* - Client Finished
* - Server Verify
* - Server Finished
* - Request Certificate
* - Client Certificate
*
* - Decryption is supported only for session that use RSA key exchange,
* if the host private key is provided via preference.
*
* - Decryption need to be performed 'sequentially', so it's done
* at packet reception time. This may cause a significative packet capture
* slow down. This also cause do dissect some ssl info that in previous
* dissector version were dissected only when a proto_tree context was
* available
*
* We are at Packet reception if time pinfo->fd->[Link] == 0
*
*/

[Portion of code removed by course developer; see [Link] in the \misc directory of the Student
Supplement DVD.]

WSU04: Network Forensics and Security – Appendix C Page C-3


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

/*********************************************************************
*

* Main dissector
*
*********************************************************************/
/*
* Code to actually dissect the packets
*/
static void
dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

conversation_t *conversation;
void *conv_data;
proto_item *ti;
proto_tree *ssl_tree;
guint32 offset;
gboolean first_record_in_frame;
gboolean need_desegmentation;
SslDecryptSession* ssl_session;
guint* conv_version;
ti = NULL;
ssl_tree = NULL;
offset = 0;
first_record_in_frame = TRUE;
ssl_session = NULL;

ssl_debug_printf("\ndissect_ssl enter frame #%u (%s)\n", pinfo->fd->num, (pinfo->fd-


>[Link])?"already visited":"first time");

/* Track the version using conversations to reduce the


* chance that a packet that simply *looks* like a v2 or
* v3 packet is dissected improperly. This also allows
* us to more frequently set the protocol column properly
* for continuation data frames.
*
* Also: We use the copy in conv_version as our cached copy,
* so that we don't have to search the conversation
* table every time we want the version; when setting
* the conv_version, must set the copy in the conversation
* in addition to conv_version
*/
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo-
>ptype,
pinfo->srcport, pinfo->destport, 0);

if (!conversation)
{
/* create a new conversation */
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo-
>ptype,
pinfo->srcport, pinfo->destport, 0);
}
conv_data = conversation_get_proto_data(conversation, proto_ssl);

/* PAOLO: manage ssl decryption data */


/*get a valid ssl session pointer*/
if (conv_data != NULL)
ssl_session = conv_data;
else {
SslService dummy;

ssl_session = se_alloc0(sizeof(SslDecryptSession));
ssl_session_init(ssl_session);
ssl_session->version = SSL_VER_UNKNOWN;
conversation_add_proto_data(conversation, proto_ssl, ssl_session);

WSU04: Network Forensics and Security – Appendix C Page C-4


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

/* we need to know witch side of conversation is speaking*/


if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype ==
PT_TCP)) {
[Link] = pinfo->src;
[Link] = pinfo->srcport;
}
else {
[Link] = pinfo->dst;
[Link] = pinfo->destport;
}
ssl_debug_printf("dissect_ssl server %hhu.%hhu.%hhu.%hhu:%u\n",
[Link][0],
[Link][1],[Link][2],
[Link][3],[Link]);

/* try to retrive private key for this service. Do it now 'cause pinfo
* is not always available
* Note that with HAVE_LIBGNUTLS undefined private_key is allways 0
* and thus decryption never engaged*/
ssl_session->private_key = g_hash_table_lookup(ssl_key_hash, &dummy);
if (!ssl_session->private_key)
ssl_debug_printf("dissect_ssl can't find private key for this server!\n");
}
conv_version= & ssl_session->version;

/* try decryption only the first time we see this packet


* (to keep cipher syncronized)and only if we have
* the server private key*/
if (pinfo->fd->[Link])
ssl_session = NULL;

/* Initialize the protocol column; we'll set it later when we


* figure out what flavor of SSL it is (assuming we don't
* throw an exception before we get the chance to do so). */
if (check_col(pinfo->cinfo, COL_PROTOCOL))
{
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSL");
}
/* clear the the info column */
if (check_col(pinfo->cinfo, COL_INFO))
col_clear(pinfo->cinfo, COL_INFO);

/* TCP packets and SSL records are orthogonal.


* A tcp packet may contain multiple ssl records and an ssl
* record may be spread across multiple tcp packets.
*
* This loop accounts for multiple ssl records in a single
* frame, but not a single ssl record across multiple tcp
* packets.
*
* Handling the single ssl record across multiple packets
* may be possible using wireshark conversations, but
* probably not cleanly. May have to wait for tcp stream
* reassembly.
*/

/* Create display subtree for SSL as a whole */


if (tree)
{
ti = proto_tree_add_item(tree, proto_ssl, tvb, 0, -1, FALSE);
ssl_tree = proto_item_add_subtree(ti, ett_ssl);
}
/* iterate through the records in this tvbuff */
while (tvb_reported_length_remaining(tvb, offset) != 0)
{
/* on second and subsequent records per frame
* add a delimiter on info column
*/
if (!first_record_in_frame
&& check_col(pinfo->cinfo, COL_INFO))
{

WSU04: Network Forensics and Security – Appendix C Page C-5


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

col_append_str(pinfo->cinfo, COL_INFO, ", ");


}

/*
* Assume, for now, that this doesn't need desegmentation.
*/
need_desegmentation = FALSE;

/* first try to dispatch off the cached version


* known to be associated with the conversation
*/
switch(*conv_version) {
case SSL_VER_SSLv2:
case SSL_VER_PCT:
offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
offset, conv_version,
&need_desegmentation,
ssl_session);
break;

case SSL_VER_SSLv3:
case SSL_VER_TLS:
/* the version tracking code works too well ;-)
* at times, we may visit a v2 client hello after
* we already know the version of the connection;
* work around that here by detecting and calling
* the v2 dissector instead
*/
if (ssl_is_v2_client_hello(tvb, offset))
{
offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
offset, conv_version,
&need_desegmentation,
ssl_session);
}
else
{
offset = dissect_ssl3_record(tvb, pinfo, ssl_tree,
offset, conv_version,
&need_desegmentation,
ssl_session,
first_record_in_frame);
}
break;

/* that failed, so apply some heuristics based


* on this individual packet
*/
default:
if (ssl_looks_like_sslv2(tvb, offset))
{
/* looks like sslv2 or pct client hello */
offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
offset, conv_version,
&need_desegmentation,
ssl_session);
}
else if (ssl_looks_like_sslv3(tvb, offset))
{
/* looks like sslv3 or tls */
offset = dissect_ssl3_record(tvb, pinfo, ssl_tree,
offset, conv_version,
&need_desegmentation,
ssl_session,
first_record_in_frame);
}
else
{
/* looks like something unknown, so lump into
* continuation data
*/

WSU04: Network Forensics and Security – Appendix C Page C-6


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

offset = tvb_length(tvb);
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO,
"Continuation Data");

/* Set the protocol column */


if (check_col(pinfo->cinfo, COL_PROTOCOL))
{
col_set_str(pinfo->cinfo, COL_PROTOCOL,
ssl_version_short_names[*conv_version]);
}
}
break;
}

/* Desegmentation return check */


if (need_desegmentation)
return;
/* set up for next record in frame, if any */
first_record_in_frame = FALSE;
}
if (check_col(pinfo->cinfo, COL_INFO))
col_set_fence(pinfo->cinfo, COL_INFO);
tap_queue_packet(ssl_tap, pinfo, (gpointer)proto_ssl);
}

static gint
decrypt_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, guint32 offset,
guint32 record_length, guint8 content_type, SslDecryptSession* ssl,
gboolean save_plaintext)
{
gint ret;
gint direction;
StringInfo* data_for_iv;
gint data_for_iv_len;
SslDecoder* decoder;
ret = 0;
/* if we can decrypt and decryption have success
* add decrypted data to this packet info*/
ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl, state 0x%02X\n",
record_length, ssl->state);
direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype ==
PT_TCP);
if (!(ssl->state & SSL_HAVE_SESSION_KEY)) {
ssl_debug_printf("decrypt_ssl3_record: no session key\n");
/* save data to update IV if session key is obtained later */
data_for_iv = (direction != 0) ? &ssl->server_data_for_iv : &ssl-
>client_data_for_iv;
data_for_iv_len = (record_length < 24) ? record_length : 24;
ssl_data_set(data_for_iv, (guchar*)tvb_get_ptr(tvb, offset + record_length -
data_for_iv_len, data_for_iv_len), data_for_iv_len);
return ret;
}

/* retrive decoder for this packet direction*/


if (direction != 0) {
ssl_debug_printf("decrypt_ssl3_record: using server decoder\n");
decoder = &ssl->server;
}
else {
ssl_debug_printf("decrypt_ssl3_record: using client decoder\n");
decoder = &ssl->client;
}

/* ensure we have enough storage space for decrypted data */


if (record_length > ssl_decrypted_data.data_len)
{
ssl_debug_printf("decrypt_ssl3_record: allocating %d bytes"
" for decrypt data (old len %d)\n",
record_length + 32, ssl_decrypted_data.data_len);
ssl_decrypted_data.data = g_realloc(ssl_decrypted_data.data,

WSU04: Network Forensics and Security – Appendix C Page C-7


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

record_length + 32);
ssl_decrypted_data.data_len = record_length + 32;
}

/* run decryption and add decrypted payload to protocol data, if decryption


* is successful*/
ssl_decrypted_data_avail = ssl_decrypted_data.data_len;
if (ssl_decrypt_record(ssl, decoder,
content_type, tvb_get_ptr(tvb, offset, record_length),
record_length, ssl_decrypted_data.data, &ssl_decrypted_data_avail) == 0)
ret = 1;
/* */
if (!ret) {
/* save data to update IV if valid session key is obtained later */
data_for_iv = (direction != 0) ? &ssl->server_data_for_iv : &ssl-
>client_data_for_iv;
data_for_iv_len = (record_length < 24) ? record_length : 24;
ssl_data_set(data_for_iv, (guchar*)tvb_get_ptr(tvb, offset + record_length -
data_for_iv_len, data_for_iv_len), data_for_iv_len);
}
if (ret && save_plaintext) {
ssl_add_data_info(proto_ssl, pinfo, ssl_decrypted_data.data,
ssl_decrypted_data_avail, TVB_RAW_OFFSET(tvb)+offset, decoder->byte_seq);
decoder->byte_seq += ssl_decrypted_data_avail;
}
return ret;
}

void
dissect_ssl_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree,
SslAssociation* association)
{
gboolean save_fragmented;
SslDataInfo *appl_data;
proto_tree *ti;
tvbuff_t *next_tvb;

/* show decrypted data info, if available */


appl_data = ssl_get_data_info(proto_ssl, pinfo, TVB_RAW_OFFSET(tvb)+offset);
if (!appl_data || !appl_data->plain_data.data_len) return;

/* try to dissect decrypted data*/


ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", appl_data-
>plain_data.data_len);

/* create a new TVB structure for desegmented data */


next_tvb = tvb_new_real_data(appl_data->plain_data.data, appl_data-
>plain_data.data_len, appl_data->plain_data.data_len);

/* add this tvb as a child to the original one */


tvb_set_child_real_data_tvbuff(tvb, next_tvb);

/* add desegmented data to the data source list */


add_new_data_source(pinfo, next_tvb, "Decrypted SSL data");

/* Can we desegment this segment? */


if (FALSE /*ssl_desegment_app_data ignore till implemented well */) {
/* Yes. */
/*desegment_ssl(next_tvb, pinfo, offset, seq, nxtseq, sport, dport, tree,
tcp_tree, tcpd);*/
} else if (association && association->handle) {
/* No - just call the subdissector.
Mark this as fragmented, so if somebody throws an exception,
we don't report it as a malformed frame. */
save_fragmented = pinfo->fragmented;
pinfo->fragmented = TRUE;
ssl_debug_printf("dissect_ssl3_record found association %p\n", association);
ssl_print_text_data("decrypted app data fragment", appl_data->plain_data.data,
appl_data->plain_data.data_len);
call_dissector(association->handle, next_tvb, pinfo, proto_tree_get_root(tree));
pinfo->fragmented = save_fragmented;

WSU04: Network Forensics and Security – Appendix C Page C-8


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

}
}

/*********************************************************************
*

* SSL version 3 and TLS Dissection Routines


*
*********************************************************************/
static gint
dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset,
guint *conv_version, gboolean *need_desegmentation,
SslDecryptSession* ssl, gboolean first_record_in_frame)
{

/*
* struct {
* uint8 major, minor;
* } ProtocolVersion;
*
*
* enum {
* change_cipher_spec(20), alert(21), handshake(22),
* application_data(23), (255)
* } ContentType;
*
* struct {
* ContentType type;
* ProtocolVersion version;
* uint16 length;
* opaque fragment[[Link]];
* } TLSPlaintext;
*/
guint32 record_length;
guint16 version;
guint8 content_type;
guint8 next_byte;
proto_tree *ti;
proto_tree *ssl_record_tree;
SslAssociation* association;
guint32 available_bytes;
ti = NULL;
ssl_record_tree = NULL;
available_bytes = 0;

available_bytes = tvb_length_remaining(tvb, offset);

/* TLS 1.0/1.1 just ignores unknown records - RFC 2246 chapter 6. The TLS Record
Protocol */
if ((*conv_version==SSL_VER_TLS || *conv_version==SSL_VER_TLSv1DOT1) &&
(available_bytes >=1 ) && !ssl_is_valid_content_type(tvb_get_guint8(tvb,
offset))) {
proto_tree_add_text(tree, tvb, offset, available_bytes, "Ignored Unknown Record");
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Ignored Unknown Record");
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, ssl_version_short_names[*conv_version]);
return offset + available_bytes;
}

/*
* Can we do reassembly?
*/
if (ssl_desegment && pinfo->can_desegment) {
/*
* Yes - is the record header split across segment boundaries?
*/
if (available_bytes < 5) {
WSU04: Network Forensics and Security – Appendix C Page C-9
© 2007 Protocol Analysis Institute, Inc.
Wireshark University

/*
* Yes. Tell the TCP dissector where the data for this
* message starts in the data it handed us, and how many
* more bytes we need, and return.
*/
pinfo->desegment_offset = offset;
pinfo->desegment_len = 5 - available_bytes;
*need_desegmentation = TRUE;
return offset;
}
}

/*
* Get the record layer fields of interest
*/
content_type = tvb_get_guint8(tvb, offset);
version = tvb_get_ntohs(tvb, offset + 1);
record_length = tvb_get_ntohs(tvb, offset + 3);

if (ssl_is_valid_content_type(content_type)) {

/*
* Can we do reassembly?
*/
if (ssl_desegment && pinfo->can_desegment) {
/*
* Yes - is the record split across segment boundaries?
*/
if (available_bytes < record_length + 5) {
/*
* Yes. Tell the TCP dissector where the data for this
* message starts in the data it handed us, and how many
* more bytes we need, and return.
*/
pinfo->desegment_offset = offset;
pinfo->desegment_len = (record_length + 5) - available_bytes;
*need_desegmentation = TRUE;
return offset;
}
}

} else {

/* if we don't have a valid content_type, there's no sense


* continuing any further
*/
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Continuation Data");

/* Set the protocol column */


if (check_col(pinfo->cinfo, COL_PROTOCOL))
{
col_set_str(pinfo->cinfo, COL_PROTOCOL,
ssl_version_short_names[*conv_version]);
}
return offset + 5 + record_length;
}

/*
* If GUI, fill in record layer part of tree
*/
if (tree)
{

/* add the record layer subtree header */


tvb_ensure_bytes_exist(tvb, offset, 5 + record_length);
ti = proto_tree_add_item(tree, hf_ssl_record, tvb,
offset, 5 + record_length, 0);
ssl_record_tree = proto_item_add_subtree(ti, ett_ssl_record);
}
if (ssl_record_tree)

WSU04: Network Forensics and Security – Appendix C Page C-10


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

/* show the one-byte content type */


proto_tree_add_item(ssl_record_tree, hf_ssl_record_content_type,
tvb, offset, 1, 0);
offset++;

/* add the version */


proto_tree_add_item(ssl_record_tree, hf_ssl_record_version, tvb,
offset, 2, FALSE);
offset += 2;

/* add the length */


proto_tree_add_uint(ssl_record_tree, hf_ssl_record_length, tvb,
offset, 2, record_length);
offset += 2; /* move past length field itself */
}
else
{
/* if no GUI tree, then just skip over those fields */
offset += 5;
}

/*
* if we don't already have a version set for this conversation,
* but this message's version is authoritative (i.e., it's
* not client_hello, then save the version to to conversation
* structure and print the column version
*/
next_byte = tvb_get_guint8(tvb, offset);
if (*conv_version == SSL_VER_UNKNOWN
&& ssl_is_authoritative_version_message(content_type, next_byte))
{
if (version == SSLV3_VERSION)
{
*conv_version = SSL_VER_SSLv3;
if (ssl) {
ssl->version_netorder = version;
ssl->state |= SSL_VERSION;
ssl_debug_printf("dissect_ssl3_record found version 0x%04X -> state
0x%02X\n", ssl->version_netorder, ssl->state);
}
/*ssl_set_conv_version(pinfo, ssl->version);*/
}
else if (version == TLSV1_VERSION)
{

*conv_version = SSL_VER_TLS;
if (ssl) {
ssl->version_netorder = version;
ssl->state |= SSL_VERSION;
ssl_debug_printf("dissect_ssl3_record found version 0x%04X -> state
0x%02X\n", ssl->version_netorder, ssl->state);
}
/*ssl_set_conv_version(pinfo, ssl->version);*/
}
else if (version == TLSV1DOT1_VERSION)
{

*conv_version = SSL_VER_TLSv1DOT1;
if (ssl) {
ssl->version_netorder = version;
ssl->state |= SSL_VERSION;
ssl_debug_printf("dissect_ssl3_record found version 0x%04X -> state
0x%02X\n", ssl->version_netorder, ssl->state);
}
/*ssl_set_conv_version(pinfo, ssl->version);*/
}
}
if (check_col(pinfo->cinfo, COL_PROTOCOL))

WSU04: Network Forensics and Security – Appendix C Page C-11


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

{
col_set_str(pinfo->cinfo, COL_PROTOCOL,
ssl_version_short_names[*conv_version]);
}

/*
* now dissect the next layer
*/
ssl_debug_printf("dissect_ssl3_record: content_type %d\n",content_type);

/* PAOLO try to decrypt each record (we must keep ciphers "in sync")
* store plain text only for app data */

switch (content_type) {
case SSL_ID_CHG_CIPHER_SPEC:
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree,
offset, conv_version, content_type);
ssl_debug_printf("dissect_ssl3_change_cipher_spec\n");
break;
case SSL_ID_ALERT:
{
tvbuff_t* decrypted;
decrypted=0;
if (ssl&&decrypt_ssl3_record(tvb, pinfo, offset,
record_length, content_type, ssl, FALSE))
ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data,
ssl_decrypted_data_avail, offset);

/* try to retrive and use decrypted alert record, if any. */


decrypted = ssl_get_record_info(proto_ssl, pinfo, offset);
if (decrypted)
dissect_ssl3_alert(decrypted, pinfo, ssl_record_tree, 0,
conv_version);
else
dissect_ssl3_alert(tvb, pinfo, ssl_record_tree, offset,
conv_version);
break;
}
case SSL_ID_HANDSHAKE:
{
tvbuff_t* decrypted;
decrypted=0;
/* try to decrypt handshake record, if possible. Store decrypted
* record for later usage. The offset is used as 'key' to itentify
* this record into the packet (we can have multiple handshake records
* in the same frame) */
if (ssl && decrypt_ssl3_record(tvb, pinfo, offset,
record_length, content_type, ssl, FALSE))
ssl_add_record_info(proto_ssl, pinfo, ssl_decrypted_data.data,
ssl_decrypted_data_avail, offset);

/* try to retrive and use decrypted handshake record, if any. */


decrypted = ssl_get_record_info(proto_ssl, pinfo, offset);
if (decrypted) {
/* add desegmented data to the data source list */
add_new_data_source(pinfo, decrypted, "Decrypted SSL record");
dissect_ssl3_handshake(decrypted, pinfo, ssl_record_tree, 0,
decrypted->length, conv_version, ssl, content_type);
} else {
dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset,
record_length, conv_version, ssl, content_type);
}
break;
}
case SSL_ID_APP_DATA:
if (ssl){
decrypt_ssl3_record(tvb, pinfo, offset,
record_length, content_type, ssl, TRUE);
/* if application data desegmentation is allowed and needed */

WSU04: Network Forensics and Security – Appendix C Page C-12


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

/*if(ssl_desegment_app_data && *need_desegmentation)


ssl_desegment_ssl_app_data(ssl,pinfo);
*/
}

/* show on info colum what we are decoding */


if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Application Data");

/* we need dissector information when the selected packet is shown.


* ssl session pointer is NULL at that time, so we can't access
* info cached there*/
association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype
== PT_TCP);
association = association ? association: ssl_association_find(ssl_associations,
pinfo->destport, pinfo->ptype == PT_TCP);

proto_item_set_text(ssl_record_tree,
"%s Record Layer: %s Protocol: %s",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type, "unknown"),
association?association->info:"Application Data");

proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb,


offset, record_length, 0);

dissect_ssl_payload(tvb, pinfo, offset, tree, association);

break;

default:
/* shouldn't get here since we check above for valid types */
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Bad SSLv3 Content Type");
break;
}
offset += record_length; /* skip to end of record */

return offset;
}

/* dissects the change cipher spec procotol, filling in the tree */


static void
dissect_ssl3_change_cipher_spec(tvbuff_t *tvb,
proto_tree *tree, guint32 offset,
guint* conv_version, guint8 content_type)
{
/*
* struct {
* enum { change_cipher_spec(1), (255) } type;
* } ChangeCipherSpec;
*
*/
if (tree)
{
proto_item_set_text(tree,
"%s Record Layer: %s Protocol: Change Cipher Spec",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type, "unknown"));
proto_tree_add_item(tree, hf_ssl_change_cipher_spec, tvb,
offset++, 1, FALSE);
}
}

/* dissects the alert message, filling in the tree */


static void
dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, guint32 offset,
guint* conv_version)
{
/* struct {

WSU04: Network Forensics and Security – Appendix C Page C-13


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

* AlertLevel level;
* AlertDescription description;
* } Alert;
*/
proto_tree *ti;
proto_tree *ssl_alert_tree;
const gchar *level;
const gchar *desc;
guint8 byte;
ssl_alert_tree = NULL;
if (tree)
{
ti = proto_tree_add_item(tree, hf_ssl_alert_message, tvb,
offset, 2, 0);
ssl_alert_tree = proto_item_add_subtree(ti, ett_ssl_alert);
}

/*
* set the record layer label
*/

/* first lookup the names for the alert level and description */
byte = tvb_get_guint8(tvb, offset); /* grab the level byte */
level = match_strval(byte, ssl_31_alert_level);

byte = tvb_get_guint8(tvb, offset+1); /* grab the desc byte */


desc = match_strval(byte, ssl_31_alert_description);

/* now set the text in the record layer line */


if (level && desc)
{
if (check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO,
"Alert (Level: %s, Description: %s)",
level, desc);
}
else
{
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, "Encrypted Alert");
}

if (tree)
{
if (level && desc)
{
proto_item_set_text(tree, "%s Record Layer: Alert "
"(Level: %s, Description: %s)",
ssl_version_short_names[*conv_version],
level, desc);
proto_tree_add_item(ssl_alert_tree, hf_ssl_alert_message_level,
tvb, offset++, 1, FALSE);

proto_tree_add_item(ssl_alert_tree, hf_ssl_alert_message_description,
tvb, offset++, 1, FALSE);
}
else
{
proto_item_set_text(tree,
"%s Record Layer: Encrypted Alert",
ssl_version_short_names[*conv_version]);
proto_item_set_text(ssl_alert_tree,
"Alert Message: Encrypted Alert");
}
}
}

/* dissects the handshake protocol, filling the tree */


static void
dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,

WSU04: Network Forensics and Security – Appendix C Page C-14


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

proto_tree *tree, guint32 offset,


guint32 record_length, guint *conv_version,
SslDecryptSession* ssl, guint8 content_type)
{
/* struct {
* HandshakeType msg_type;
* uint24 length;
* select (HandshakeType) {
* case hello_request: HelloRequest;
* case client_hello: ClientHello;
* case server_hello: ServerHello;
* case certificate: Certificate;
* case server_key_exchange: ServerKeyExchange;
* case certificate_request: CertificateRequest;
* case server_hello_done: ServerHelloDone;
* case certificate_verify: CertificateVerify;
* case client_key_exchange: ClientKeyExchange;
* case finished: Finished;
* } body;
* } Handshake;
*/
proto_tree *ti;
proto_tree *ssl_hand_tree;
const gchar *msg_type_str;
guint8 msg_type;
guint32 length;
gboolean first_iteration;
ti = NULL;
ssl_hand_tree = NULL;
msg_type_str = NULL;
first_iteration = TRUE;

/* just as there can be multiple records per packet, there


* can be multiple messages per record as long as they have
* the same content type
*
* we really only care about this for handshake messages
*/

/* set record_length to the max offset */


record_length += offset;
while (offset < record_length)
{
msg_type = tvb_get_guint8(tvb, offset);
msg_type_str = match_strval(msg_type, ssl_31_handshake_type);
length = tvb_get_ntoh24(tvb, offset + 1);

ssl_debug_printf("dissect_ssl3_handshake iteration %d type %d offset %d length %d


"
"bytes, remaining %d \n", first_iteration, msg_type, offset, length,
record_length);
if (!msg_type_str && !first_iteration)
{
/* only dissect / report messages if they're
* either the first message in this record
* or they're a valid message type
*/
return;
}

/* on second and later iterations, add comma to info col */


if (!first_iteration)
{
if (check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO, ", ");
}

/*
* Update our info string
*/
if (check_col(pinfo->cinfo, COL_INFO))

WSU04: Network Forensics and Security – Appendix C Page C-15


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

col_append_fstr(pinfo->cinfo, COL_INFO, "%s", (msg_type_str != NULL)


? msg_type_str : "Encrypted Handshake Message");

if (tree)
{
/* set the label text on the record layer expanding node */
if (first_iteration)
{
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type,
"unknown"),
(msg_type_str!=NULL) ? msg_type_str :
"Encrypted Handshake Message");
}
else
{
proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s",
ssl_version_short_names[*conv_version],
val_to_str(content_type, ssl_31_content_type,
"unknown"),
"Multiple Handshake Messages");
}

/* add a subtree for the handshake protocol */


ti = proto_tree_add_item(tree, hf_ssl_handshake_protocol, tvb,
offset, length + 4, 0);
ssl_hand_tree = proto_item_add_subtree(ti, ett_ssl_handshake);

if (ssl_hand_tree)
{
/* set the text label on the subtree node */
proto_item_set_text(ssl_hand_tree, "Handshake Protocol: %s",
(msg_type_str != NULL) ? msg_type_str :
"Encrypted Handshake Message");
}
}

/* if we don't have a valid handshake type, just quit dissecting */


if (!msg_type_str)
return;

/* PAOLO: if we are doing ssl decryption we must dissect some requests type */
if (ssl_hand_tree || ssl)
{
/* add nodes for the message type and message length */
if (ssl_hand_tree)
proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type,
tvb, offset, 1, msg_type);
offset++;
if (ssl_hand_tree)
proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length,
tvb, offset, 3, length);
offset += 3;

/* now dissect the handshake message, if necessary */


switch (msg_type) {
case SSL_HND_HELLO_REQUEST:
/* hello_request has no fields, so nothing to do! */
break;

case SSL_HND_CLIENT_HELLO:
dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl);
break;

case SSL_HND_SERVER_HELLO:
dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl);
break;

case SSL_HND_CERTIFICATE:
dissect_ssl3_hnd_cert(tvb, ssl_hand_tree, offset, pinfo);

WSU04: Network Forensics and Security – Appendix C Page C-16


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

break;

case SSL_HND_SERVER_KEY_EXCHG:
/* unimplemented */
break;

case SSL_HND_CERT_REQUEST:
dissect_ssl3_hnd_cert_req(tvb, ssl_hand_tree, offset);
break;

case SSL_HND_SVR_HELLO_DONE:
/* server_hello_done has no fields, so nothing to do! */
break;

case SSL_HND_CERT_VERIFY:
/* unimplemented */
break;

case SSL_HND_CLIENT_KEY_EXCHG:
{
/* PAOLO: here we can have all the data to build session key*/
StringInfo encrypted_pre_master;
gint ret;
guint encrlen, skip;
encrlen = length;
skip = 0;

if (!ssl)
break;

/* check for required session data */


ssl_debug_printf("dissect_ssl3_handshake found
SSL_HND_CLIENT_KEY_EXCHG state 0x%X\n",
ssl->state);
if ((ssl->state &
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) !=
(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION))
{
ssl_debug_printf("dissect_ssl3_handshake not enough data to
generate key (required 0x%02X)\n",

(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION));
break;
}

/* get encrypted data, on tls1 we have to skip two bytes


* (it's the encrypted len and should be equal to record len - 2)
*/
if (ssl->version == SSL_VER_TLS||ssl->version == SSL_VER_TLSv1DOT1)
{
encrlen = tvb_get_ntohs(tvb, offset);
skip = 2;
if (encrlen > length - 2)
{
ssl_debug_printf("dissect_ssl3_handshake wrong encrypted
length (%d max %d)\n",
encrlen, length);
break;
}
}
encrypted_pre_master.data = se_alloc(encrlen);
encrypted_pre_master.data_len = encrlen;
tvb_memcpy(tvb, encrypted_pre_master.data, offset+skip, encrlen);

if (!ssl->private_key) {
ssl_debug_printf("dissect_ssl3_handshake can't find private
key\n");
break;
}

/* go with ssl key processessing; encrypted_pre_master

WSU04: Network Forensics and Security – Appendix C Page C-17


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

* will be used for master secret store*/


ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl-
>private_key);
if (ret < 0) {
ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master
secret\n");
break;
}
if (ssl_generate_keyring_material(ssl)<0) {
ssl_debug_printf("dissect_ssl3_handshake can't generate keyring
material\n");
break;
}
ssl->state |= SSL_HAVE_SESSION_KEY;
ssl_save_session(ssl, ssl_session_hash);
ssl_debug_printf("dissect_ssl3_handshake session keys succesfully
generated\n");
}
break;

case SSL_HND_FINISHED:
dissect_ssl3_hnd_finished(tvb, ssl_hand_tree,
offset, conv_version);
break;
}

}
else
offset += 4; /* skip the handshake header when handshake is not
processed*/

offset += length;
first_iteration = FALSE; /* set up for next pass, if any */
}
}

static gint
dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree,
guint32 offset, SslDecryptSession* ssl, gint from_server)
{
/* show the client's random challenge */
nstime_t gmt_unix_time;
guint8 session_id_length;
proto_item *ti_rnd;
proto_tree *ssl_rnd_tree;

session_id_length = 0;

if (ssl)
{
/* PAOLO: get proper peer information*/
StringInfo* rnd;
if (from_server)
rnd = &ssl->server_random;
else
rnd = &ssl->client_random;

/* get provided random for keyring generation*/


tvb_memcpy(tvb, rnd->data, offset, 32);
rnd->data_len = 32;
if (from_server)
ssl->state |= SSL_SERVER_RANDOM;
else
ssl->state |= SSL_CLIENT_RANDOM;
ssl_debug_printf("dissect_ssl3_hnd_hello_common found %s RANDOM -> state
0x%02X\n",
(from_server)?"SERVER":"CLIENT", ssl->state);

session_id_length = tvb_get_guint8(tvb, offset + 32);


/* check stored session id info */
if (from_server && (session_id_length == ssl->session_id.data_len) &&

WSU04: Network Forensics and Security – Appendix C Page C-18


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

(tvb_memeql(tvb, offset+33, ssl->session_id.data, session_id_length) ==


0))
{
/* clinet/server id match: try to restore a previous cached session*/
ssl_restore_session(ssl, ssl_session_hash);
}
else {
tvb_memcpy(tvb,ssl->session_id.data, offset+33, session_id_length);
ssl->session_id.data_len = session_id_length;
}
}

if (tree)
{
ti_rnd = proto_tree_add_text(tree, tvb, offset, 32, "Random");
ssl_rnd_tree = proto_item_add_subtree(ti_rnd, ett_ssl_random);

/* show the time */


gmt_unix_time.secs = tvb_get_ntohl(tvb, offset);
gmt_unix_time.nsecs = 0;
proto_tree_add_time(ssl_rnd_tree, hf_ssl_handshake_random_time,
tvb, offset, 4, &gmt_unix_time);
offset += 4;

/* show the random bytes */


proto_tree_add_item(ssl_rnd_tree, hf_ssl_handshake_random_bytes,
tvb, offset, 28, FALSE);
offset += 28;

/* show the session id */


session_id_length = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_ssl_handshake_session_id_len,
tvb, offset++, 1, 0);
if (session_id_length > 0)
{
tvb_ensure_bytes_exist(tvb, offset, session_id_length);
proto_tree_add_bytes(tree, hf_ssl_handshake_session_id,
tvb, offset, session_id_length,
tvb_get_ptr(tvb, offset, session_id_length));
offset += session_id_length;
}

/* XXXX */
return session_id_length+33;
}

static gint
dissect_ssl3_hnd_hello_ext(tvbuff_t *tvb,
proto_tree *tree, guint32 offset, guint32 left)
{
guint16 extension_length;
guint16 ext_type;
guint16 ext_len;
proto_item *pi;
proto_tree *ext_tree;

if (left < 2)
return offset;

extension_length = tvb_get_ntohs(tvb, offset);


proto_tree_add_uint(tree, hf_ssl_handshake_extensions_len,
tvb, offset, 2, extension_length);
offset += 2;
left -= 2;

while (left >= 4)


{
ext_type = tvb_get_ntohs(tvb, offset);
ext_len = tvb_get_ntohs(tvb, offset + 2);

WSU04: Network Forensics and Security – Appendix C Page C-19


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

pi = proto_tree_add_text(tree, tvb, offset, 4 + ext_len,


"Extension: %s",
val_to_str(ext_type,
tls_hello_extension_types,
"Unknown %u"));
ext_tree = proto_item_add_subtree(pi, ett_ssl_extension);
if (!ext_tree)
ext_tree = tree;

proto_tree_add_uint(ext_tree, hf_ssl_handshake_extension_type,
tvb, offset, 2, ext_type);
offset += 2;

proto_tree_add_uint(ext_tree, hf_ssl_handshake_extension_len,
tvb, offset, 2, ext_len);
offset += 2;

proto_tree_add_bytes_format(ext_tree, hf_ssl_handshake_extension_data,
tvb, offset, ext_len,
tvb_get_ptr(tvb, offset, ext_len),
"Data (%u byte%s)",
ext_len, plurality(ext_len, "", "s"));
offset += ext_len;
left -= 2 + 2 + ext_len;
}

return offset;
}

static void
dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb,
proto_tree *tree, guint32 offset, guint32 length,
SslDecryptSession*ssl)
{
/* struct {
* ProtocolVersion client_version;
* Random random;
* SessionID session_id;
* CipherSuite cipher_suites<2..2^16-1>;
* CompressionMethod compression_methods<1..2^8-1>;
* Extension client_hello_extension_list<0..2^16-1>;
* } ClientHello;
*
*/
proto_tree *ti;
proto_tree *cs_tree;
guint16 cipher_suite_length;
guint8 compression_methods_length;
guint8 compression_method;
guint16 start_offset;
cipher_suite_length = 0;
compression_methods_length = 0;
start_offset = offset;

if (tree || ssl)
{
/* show the client version */
if (tree)
proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb,
offset, 2, FALSE);
offset += 2;

/* show the fields in common with server hello */


offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 0);

/* tell the user how many cipher suites there are */


cipher_suite_length = tvb_get_ntohs(tvb, offset);
if (!tree)
return;
proto_tree_add_uint(tree, hf_ssl_handshake_cipher_suites_len,

WSU04: Network Forensics and Security – Appendix C Page C-20


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

tvb, offset, 2, cipher_suite_length);


offset += 2; /* skip opaque length */

if (cipher_suite_length > 0)
{
tvb_ensure_bytes_exist(tvb, offset, cipher_suite_length);
ti = proto_tree_add_none_format(tree,
hf_ssl_handshake_cipher_suites,
tvb, offset, cipher_suite_length,
"Cipher Suites (%u suite%s)",
cipher_suite_length / 2,
plurality(cipher_suite_length/2, "", "s"));

/* make this a subtree */


cs_tree = proto_item_add_subtree(ti, ett_ssl_cipher_suites);
if (!cs_tree)
{
cs_tree = tree; /* failsafe */
}

while (cipher_suite_length > 0)


{
proto_tree_add_item(cs_tree, hf_ssl_handshake_cipher_suite,
tvb, offset, 2, FALSE);
offset += 2;
cipher_suite_length -= 2;
}
}

/* tell the user how man compression methods there are */


compression_methods_length = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_ssl_handshake_comp_methods_len,
tvb, offset, 1, compression_methods_length);
offset++;

if (compression_methods_length > 0)
{
tvb_ensure_bytes_exist(tvb, offset, compression_methods_length);
ti = proto_tree_add_none_format(tree,
hf_ssl_handshake_comp_methods,
tvb, offset, compression_methods_length,
"Compression Methods (%u method%s)",
compression_methods_length,
plurality(compression_methods_length,
"", "s"));

/* make this a subtree */


cs_tree = proto_item_add_subtree(ti, ett_ssl_comp_methods);
if (!cs_tree)
{
cs_tree = tree; /* failsafe */
}

while (compression_methods_length > 0)


{
compression_method = tvb_get_guint8(tvb, offset);
if (compression_method < 64)
proto_tree_add_uint(cs_tree, hf_ssl_handshake_comp_method,
tvb, offset, 1, compression_method);
else if (compression_method > 63 && compression_method < 193)
proto_tree_add_text(cs_tree, tvb, offset, 1,
"Compression Method: Reserved - to be assigned by IANA (%u)",
compression_method);
else
proto_tree_add_text(cs_tree, tvb, offset, 1,
"Compression Method: Private use range (%u)",
compression_method);
offset++;
compression_methods_length--;
}
}

WSU04: Network Forensics and Security – Appendix C Page C-21


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

if (length > offset - start_offset)


{
offset = dissect_ssl3_hnd_hello_ext(tvb, tree, offset,
length -
(offset - start_offset));
}
}
}

static void
dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb,
proto_tree *tree, guint32 offset, guint32 length,
SslDecryptSession* ssl)
{
/* struct {
* ProtocolVersion server_version;
* Random random;
* SessionID session_id;
* CipherSuite cipher_suite;
* CompressionMethod compression_method;
* Extension server_hello_extension_list<0..2^16-1>;
* } ServerHello;
*/
guint16 start_offset;
start_offset = offset;

if (tree || ssl)
{
/* show the server version */
if (tree)
proto_tree_add_item(tree, hf_ssl_handshake_server_version, tvb,
offset, 2, FALSE);
offset += 2;

/* first display the elements conveniently in


* common with client hello
*/
offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 1);

/* PAOLO: handle session cipher suite */


if (ssl) {
/* store selected cipher suite for decryption */
ssl->cipher = tvb_get_ntohs(tvb, offset);
if (ssl_find_cipher(ssl->cipher,&ssl->cipher_suite) < 0) {
ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't find cipher suite
0x%X\n", ssl->cipher);
goto no_cipher;
}

ssl->state |= SSL_CIPHER;
ssl_debug_printf("dissect_ssl3_hnd_srv_hello found CIPHER 0x%04X -> state
0x%02X\n",
ssl->cipher, ssl->state);

/* if we have restored a session now we can have enought material


* to build session key, check it out*/
if ((ssl->state &

(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) !=

(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET)) {
ssl_debug_printf("dissect_ssl3_hnd_srv_hello not enough data to generate
key (required 0x%02X)\n",

(SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION|SSL_MASTER_SECRET));
goto no_cipher;
}

ssl_debug_printf("dissect_ssl3_hnd_srv_hello trying to generate keys\n");


if (ssl_generate_keyring_material(ssl)<0) {

WSU04: Network Forensics and Security – Appendix C Page C-22


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't generate keyring


material\n");
goto no_cipher;
}
ssl->state |= SSL_HAVE_SESSION_KEY;
}
no_cipher:
if (!tree)
return;

/* now the server-selected cipher suite */


proto_tree_add_item(tree, hf_ssl_handshake_cipher_suite,
tvb, offset, 2, FALSE);
offset += 2;

/* and the server-selected compression method */


proto_tree_add_item(tree, hf_ssl_handshake_comp_method,
tvb, offset, 1, FALSE);
offset++;

if (length > offset - start_offset)


{
offset = dissect_ssl3_hnd_hello_ext(tvb, tree, offset,
length -
(offset - start_offset));
}
}
}

static void
dissect_ssl3_hnd_cert(tvbuff_t *tvb,
proto_tree *tree, guint32 offset, packet_info *pinfo)
{

/* opaque ASN.1Cert<2^24-1>;
*
* struct {
* ASN.1Cert certificate_list<1..2^24-1>;
* } Certificate;
*/
guint32 certificate_list_length;
proto_tree *ti;
proto_tree *subtree;

if (tree)
{
certificate_list_length = tvb_get_ntoh24(tvb, offset);
proto_tree_add_uint(tree, hf_ssl_handshake_certificates_len,
tvb, offset, 3, certificate_list_length);
offset += 3; /* 24-bit length value */

if (certificate_list_length > 0)
{
tvb_ensure_bytes_exist(tvb, offset, certificate_list_length);
ti = proto_tree_add_none_format(tree,
hf_ssl_handshake_certificates,
tvb, offset, certificate_list_length,
"Certificates (%u byte%s)",
certificate_list_length,
plurality(certificate_list_length,
"", "s"));

/* make it a subtree */
subtree = proto_item_add_subtree(ti, ett_ssl_certs);
if (!subtree)
{
subtree = tree; /* failsafe */
}

/* iterate through each certificate */


while (certificate_list_length > 0)

WSU04: Network Forensics and Security – Appendix C Page C-23


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

{
/* get the length of the current certificate */
guint32 cert_length;
cert_length = tvb_get_ntoh24(tvb, offset);
certificate_list_length -= 3 + cert_length;

proto_tree_add_item(subtree, hf_ssl_handshake_certificate_len,
tvb, offset, 3, FALSE);
offset += 3;

dissect_x509af_Certificate(FALSE, tvb, offset, pinfo, subtree,


hf_ssl_handshake_certificate);
offset += cert_length;
}
}

}
}

static void
dissect_ssl3_hnd_cert_req(tvbuff_t *tvb,
proto_tree *tree, guint32 offset)
{
/*
* enum {
* rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
* (255)
* } ClientCertificateType;
*
* opaque DistinguishedName<1..2^16-1>;
*
* struct {
* ClientCertificateType certificate_types<1..2^8-1>;
* DistinguishedName certificate_authorities<3..2^16-1>;
* } CertificateRequest;
*
*/
proto_tree *ti;
proto_tree *subtree;
guint8 cert_types_count;
gint dnames_length;
cert_types_count = 0;
dnames_length = 0;

if (tree)
{
cert_types_count = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_ssl_handshake_cert_types_count,
tvb, offset, 1, cert_types_count);
offset++;

if (cert_types_count > 0)
{
ti = proto_tree_add_none_format(tree,
hf_ssl_handshake_cert_types,
tvb, offset, cert_types_count,
"Certificate types (%u type%s)",
cert_types_count,
plurality(cert_types_count, "", "s"));
subtree = proto_item_add_subtree(ti, ett_ssl_cert_types);
if (!subtree)
{
subtree = tree;
}

while (cert_types_count > 0)


{
proto_tree_add_item(subtree, hf_ssl_handshake_cert_type,
tvb, offset, 1, FALSE);
offset++;
cert_types_count--;

WSU04: Network Forensics and Security – Appendix C Page C-24


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

}
}

dnames_length = tvb_get_ntohs(tvb, offset);


proto_tree_add_uint(tree, hf_ssl_handshake_dnames_len,
tvb, offset, 2, dnames_length);
offset += 2;

if (dnames_length > 0)
{
tvb_ensure_bytes_exist(tvb, offset, dnames_length);
ti = proto_tree_add_none_format(tree,
hf_ssl_handshake_dnames,
tvb, offset, dnames_length,
"Distinguished Names (%d byte%s)",
dnames_length,
plurality(dnames_length, "", "s"));
subtree = proto_item_add_subtree(ti, ett_ssl_dnames);
if (!subtree)
{
subtree = tree;
}

while (dnames_length > 0)


{
/* get the length of the current certificate */
guint16 name_length;
name_length = tvb_get_ntohs(tvb, offset);
dnames_length -= 2 + name_length;

proto_tree_add_item(subtree, hf_ssl_handshake_dname_len,
tvb, offset, 2, FALSE);
offset += 2;

tvb_ensure_bytes_exist(tvb, offset, name_length);


proto_tree_add_bytes_format(subtree,
hf_ssl_handshake_dname,
tvb, offset, name_length,
tvb_get_ptr(tvb, offset, name_length),
"Distinguished Name (%u byte%s)",
name_length,
plurality(name_length, "", "s"));
offset += name_length;
}
}
}

static void
dissect_ssl3_hnd_finished(tvbuff_t *tvb,
proto_tree *tree, guint32 offset,
guint* conv_version)
{
/* For TLS:
* struct {
* opaque verify_data[12];
* } Finished;
*
* For SSLv3:
* struct {
* opaque md5_hash[16];
* opaque sha_hash[20];
* } Finished;
*/

/* this all needs a tree, so bail if we don't have one */


if (!tree)
{
return;
}

WSU04: Network Forensics and Security – Appendix C Page C-25


© 2007 Protocol Analysis Institute, Inc.
Wireshark University

switch(*conv_version) {
case SSL_VER_TLS:
case SSL_VER_TLSv1DOT1:
proto_tree_add_item(tree, hf_ssl_handshake_finished,
tvb, offset, 12, FALSE);
break;

case SSL_VER_SSLv3:
proto_tree_add_item(tree, hf_ssl_handshake_md5_hash,
tvb, offset, 16, FALSE);
offset += 16;
proto_tree_add_item(tree, hf_ssl_handshake_sha_hash,
tvb, offset, 20, FALSE);
offset += 20;
break;
}
}

Note: This is only a portion of the code. The entire code can be found in the \misc
directory on the Student Supplement DVD.

WSU04: Network Forensics and Security – Appendix C Page C-26


© 2007 Protocol Analysis Institute, Inc.

You might also like