sensitivity of packet range options fine tuning:
[obnox/wireshark/wip.git] / packet-ssl.c
index 00ac2571ea1d37d8514c4b1b77c19fb7529a5ae3..a60b9d508b228e67d569d0d707753e547e296eff 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for ssl dissection
  * Copyright (c) 2000-2001, Scott Renfro <scott@renfro.org>
  *
- * $Id: packet-ssl.c,v 1.20 2002/04/08 10:05:19 guy Exp $
+ * $Id: packet-ssl.c,v 1.28 2003/12/07 02:26:03 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
+ * See
+ *
+ *     http://www.netscape.com/eng/security/SSL_2.html
+ *
+ * for SSL 2.0 specs.
+ * 
+ * See
+ *
+ *     http://www.netscape.com/eng/ssl3/
+ *
+ * for SSL 3.0 specs.
+ *
+ * See RFC 2246 for SSL 3.1/TLS 1.0 specs.
+ *
  * Notes:
  *
  *   - Uses conversations in a no-malloc fashion.  Since we just want to
 
 #include <glib.h>
 
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
 #include <epan/conversation.h>
 #include "prefs.h"
 
@@ -89,6 +99,7 @@ static int hf_ssl2_record                    = -1;
 static int hf_ssl2_record_is_escape          = -1;
 static int hf_ssl2_record_padding_length     = -1;
 static int hf_ssl2_msg_type                  = -1;
+static int hf_pct_msg_type                   = -1;
 static int hf_ssl_change_cipher_spec         = -1;
 static int hf_ssl_alert_message              = -1;
 static int hf_ssl_alert_message_level        = -1;
@@ -160,6 +171,7 @@ static gint ett_ssl_dnames            = -1;
 #define SSL_VER_SSLv2                     1
 #define SSL_VER_SSLv3                     2
 #define SSL_VER_TLS                       3
+#define SSL_VER_PCT                       4
 
 /* corresponds to the #defines above */
 static gchar* ssl_version_short_names[] = {
@@ -167,6 +179,7 @@ static gchar* ssl_version_short_names[] = {
     "SSLv2",
     "SSLv3",
     "TLS",
+    "PCT"
 };
 
 /* other defines */
@@ -175,16 +188,16 @@ static gchar* ssl_version_short_names[] = {
 #define SSL_ID_HANDSHAKE               0x16
 #define SSL_ID_APP_DATA                0x17
 
-#define SSL_HND_HELLO_REQUEST          0x00
-#define SSL_HND_CLIENT_HELLO           0x01
-#define SSL_HND_SERVER_HELLO           0x02
-#define SSL_HND_CERTIFICATE            0x0b
-#define SSL_HND_SERVER_KEY_EXCHG       0x0c
-#define SSL_HND_CERT_REQUEST           0x0d
-#define SSL_HND_SVR_HELLO_DONE         0x0e
-#define SSL_HND_CERT_VERIFY            0x0f
-#define SSL_HND_CLIENT_KEY_EXCHG       0x10
-#define SSL_HND_FINISHED               0x14
+#define SSL_HND_HELLO_REQUEST          0
+#define SSL_HND_CLIENT_HELLO           1
+#define SSL_HND_SERVER_HELLO           2
+#define SSL_HND_CERTIFICATE            11
+#define SSL_HND_SERVER_KEY_EXCHG       12
+#define SSL_HND_CERT_REQUEST           13
+#define SSL_HND_SVR_HELLO_DONE         14
+#define SSL_HND_CERT_VERIFY            15
+#define SSL_HND_CLIENT_KEY_EXCHG       16
+#define SSL_HND_FINISHED               20
 
 #define SSL2_HND_ERROR                 0x00
 #define SSL2_HND_CLIENT_HELLO          0x01
@@ -196,6 +209,14 @@ static gchar* ssl_version_short_names[] = {
 #define SSL2_HND_REQUEST_CERTIFICATE   0x07
 #define SSL2_HND_CLIENT_CERTIFICATE    0x08
 
+#define PCT_VERSION_1                 0x8001
+
+#define PCT_MSG_CLIENT_HELLO           0x01
+#define PCT_MSG_SERVER_HELLO           0x02
+#define PCT_MSG_CLIENT_MASTER_KEY      0x03
+#define PCT_MSG_SERVER_VERIFY          0x04
+#define PCT_MSG_ERROR                  0x05
+
 /*
  * Lookup tables
  *
@@ -253,6 +274,18 @@ static const value_string ssl_20_cipher_suites[] = {
     { 0x00001c, "SSL_FORTEZZA_KEA_WITH_NULL_SHA" },
     { 0x00001d, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA" },
     { 0x00001e, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA" },
+    { 0x00002f, "TLS_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x000030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA" },
+    { 0x000031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x000032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA" },
+    { 0x000033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x000034, "TLS_DH_anon_WITH_AES_128_CBC_SHA" },
+    { 0x000035, "TLS_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x000036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA" },
+    { 0x000037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x000038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA" },
+    { 0x000039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x00003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA" },
     { 0x000060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5" },
     { 0x000061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5" },
     { 0x000062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA" },
@@ -266,6 +299,17 @@ static const value_string ssl_20_cipher_suites[] = {
     { 0x00feff, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA" },
     { 0x00ffe0, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA" },
     { 0x00ffe1, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"},
+    /* Microsoft's old PCT protocol. These are from Eric Rescorla's
+       book "SSL and TLS" */
+    { 0x8f8001, "PCT_SSL_COMPAT | PCT_VERSION_1" },
+    { 0x800003, "PCT_SSL_CERT_TYPE | PCT1_CERT_X509_CHAIN" },
+    { 0x800001, "PCT_SSL_CERT_TYPE | PCT1_CERT_X509" },
+    { 0x810001, "PCT_SSL_HASH_TYPE | PCT1_HASH_MD5" },
+    { 0x810003, "PCT_SSL_HASH_TYPE | PCT1_HASH_SHA" },
+    { 0x820001, "PCT_SSL_EXCH_TYPE | PCT1_EXCH_RSA_PKCS1" },
+    { 0x830004, "PCT_SSL_CIPHER_TYPE_1ST_HALF | PCT1_CIPHER_RC4" },
+    { 0x848040, "PCT_SSL_CIPHER_TYPE_2ND_HALF | PCT1_ENC_BITS_128 | PCT1_MAC_BITS_128" },
+    { 0x842840, "PCT_SSL_CIPHER_TYPE_2ND_HALF | PCT1_ENC_BITS_40 | PCT1_MAC_BITS_128" },
     /* note that ciphersuites of {0x00????} are TLS cipher suites in
      * a sslv2 client hello message; the ???? above is the two-byte
      * tls cipher suite id
@@ -294,10 +338,14 @@ static const value_string ssl_versions[] = {
     { 0x00, NULL }
 };
 
+#if 0
+/* XXX - would be used if we dissected the body of a Change Cipher Spec
+   message. */
 static const value_string ssl_31_change_cipher_spec[] = {
     { 1, "Change Cipher Spec" },
     { 0x00, NULL },
 };
+#endif
 
 static const value_string ssl_31_alert_level[] = {
     { 1, "Warning" },
@@ -348,9 +396,13 @@ static const value_string ssl_31_handshake_type[] = {
 
 static const value_string ssl_31_compression_method[] = {
     { 0, "null" },
+    { 1, "ZLIB" },
     { 0x00, NULL }
 };
 
+#if 0
+/* XXX - would be used if we dissected a Signature, as would be
+   seen in a server key exchange or certificate verify message. */
 static const value_string ssl_31_key_exchange_algorithm[] = {
     { 0, "RSA" },
     { 1, "Diffie Hellman" },
@@ -363,6 +415,7 @@ static const value_string ssl_31_signature_algorithm[] = {
     { 2, "DSA" },
     { 0x00, NULL }
 };
+#endif
 
 static const value_string ssl_31_client_certificate_type[] = {
     { 1, "RSA Sign" },
@@ -372,11 +425,15 @@ static const value_string ssl_31_client_certificate_type[] = {
     { 0x00, NULL }
 };
 
+#if 0
+/* XXX - would be used if we dissected exchnage keys, as would be
+   seen in a client key exchange message. */
 static const value_string ssl_31_public_value_encoding[] = {
     { 0, "Implicit" },
     { 1, "Explicit" },
     { 0x00, NULL }
 };
+#endif
 
 static const value_string ssl_31_ciphersuite[] = {
     { 0x0000, "TLS_NULL_WITH_NULL_NULL" },
@@ -410,6 +467,18 @@ static const value_string ssl_31_ciphersuite[] = {
     { 0x001c, "SSL_FORTEZZA_KEA_WITH_NULL_SHA" },
     { 0x001d, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA" },
     { 0x001e, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA" },
+    { 0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA" },
+    { 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA" },
+    { 0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" },
+    { 0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA" },
+    { 0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA" },
+    { 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA" },
+    { 0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" },
+    { 0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA" },
     { 0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA" },
     { 0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA" },
     { 0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA" },
@@ -425,6 +494,16 @@ static const value_string ssl_31_ciphersuite[] = {
     { 0x00, NULL }
 };
 
+static const value_string pct_msg_types[] = {
+    { PCT_MSG_CLIENT_HELLO,         "Client Hello" },
+    { PCT_MSG_SERVER_HELLO,         "Server Hello" },
+    { PCT_MSG_CLIENT_MASTER_KEY,    "Client Master Key" },
+    { PCT_MSG_SERVER_VERIFY,        "Server Verify" },
+    { PCT_MSG_ERROR,                "Error" },
+    { 0x00, NULL },
+};
+
+
 /*********************************************************************
  *
  * Forward Declarations
@@ -522,6 +601,9 @@ static int  ssl_looks_like_sslv3(tvbuff_t *tvb, guint32 offset);
 static int  ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb,
                                               guint32 offset,
                                               guint32 record_length);
+static int  ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb,
+                                               guint32 offset,
+                                               guint32 record_length);
 
 /*********************************************************************
  *
@@ -567,7 +649,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     conv_data = conversation_get_proto_data(conversation, proto_ssl);
     if (conv_data != NULL)
     {
-        conv_version = (guint)conv_data;
+        conv_version = GPOINTER_TO_UINT(conv_data);
     }
 
     /* Initialize the protocol column; we'll set it later when we
@@ -625,6 +707,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
          */
         switch(conv_version) {
         case SSL_VER_SSLv2:
+        case SSL_VER_PCT:
             offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
                                          offset, &conv_version,
                                          &need_desegmentation);
@@ -658,7 +741,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         default:
             if (ssl_looks_like_sslv2(tvb, offset))
             {
-                /* looks like sslv2 client hello */
+                /* looks like sslv2 or pct client hello */
                 offset = dissect_ssl2_record(tvb, pinfo, ssl_tree,
                                              offset, &conv_version,
                                              &need_desegmentation);
@@ -698,7 +781,7 @@ dissect_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
          * this conversation, do so. */
         if (conv_data == NULL)
         {
-            conv_data = (void *)conv_version;
+            conv_data = GINT_TO_POINTER(conv_version);
             conversation_add_proto_data(conversation, proto_ssl, conv_data);
         }
 
@@ -796,9 +879,9 @@ dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo,
                 return offset;
             }
         }
-      
+
     } else {
-      
+
     /* if we don't have a valid content_type, there's no sense
      * continuing any further
      */
@@ -1162,6 +1245,10 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
                 dissect_ssl3_hnd_cert(tvb, ssl_hand_tree, offset);
                 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;
@@ -1170,16 +1257,18 @@ dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo,
                 /* server_hello_done has no fields, so nothing to do! */
                 break;
 
-            case SSL_HND_FINISHED:
-                dissect_ssl3_hnd_finished(tvb, ssl_hand_tree,
-                                          offset, conv_version);
+            case SSL_HND_CERT_VERIFY:
+                /* unimplemented */
                 break;
 
-            case SSL_HND_SERVER_KEY_EXCHG:
-            case SSL_HND_CERT_VERIFY:
             case SSL_HND_CLIENT_KEY_EXCHG:
                 /* unimplemented */
                 break;
+
+            case SSL_HND_FINISHED:
+                dissect_ssl3_hnd_finished(tvb, ssl_hand_tree,
+                                          offset, conv_version);
+                break;
             }
 
         }
@@ -1251,6 +1340,7 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb,
     proto_tree *cs_tree;
     guint16 cipher_suite_length = 0;
     guint8  compression_methods_length = 0;
+    guint8  compression_method;
 
     if (tree)
     {
@@ -1318,8 +1408,18 @@ dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb,
 
             while (compression_methods_length > 0)
             {
-                proto_tree_add_item(cs_tree, hf_ssl_handshake_comp_method,
-                                    tvb, offset, 1, FALSE);
+                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--;
             }
@@ -1593,7 +1693,7 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
      * length is three bytes due to padding; otherwise
      * record length is two bytes
      */
-    byte = tvb_get_guint8(tvb, offset++);
+    byte = tvb_get_guint8(tvb, offset);
     record_length_length = (byte & 0x80) ? 2 : 3;
 
     /*
@@ -1622,15 +1722,15 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     switch(record_length_length) {
     case 2:                     /* two-byte record length */
         record_length = (byte & 0x7f) << 8;
-        byte = tvb_get_guint8(tvb, offset++);
+        byte = tvb_get_guint8(tvb, offset + 1);
         record_length += byte;
         break;
     case 3:                     /* three-byte record length */
         is_escape = (byte & 0x40) ? TRUE : FALSE;
         record_length = (byte & 0x3f) << 8;
-        byte = tvb_get_guint8(tvb, offset++);
+        byte = tvb_get_guint8(tvb, offset + 1);
         record_length += byte;
-        byte = tvb_get_guint8(tvb, offset++);
+        byte = tvb_get_guint8(tvb, offset + 2);
         padding_length = byte;
     }
 
@@ -1641,27 +1741,20 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
         /*
          * Yes - is the record split across segment boundaries?
          */
-        if (available_bytes < record_length) {
+        if (available_bytes < (record_length_length + record_length)) {
             /*
              * 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 - available_bytes;
+            pinfo->desegment_len = (record_length_length + record_length)
+                                  - available_bytes;
             *need_desegmentation = TRUE;
             return offset;
         }
     }
-
-    /* if we get here, but don't have a version set for the
-     * conversation, then set a version for just this frame
-     * (e.g., on a client hello)
-     */
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-    {
-        col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSLv2");
-    }
+    offset += record_length_length;
 
     /* add the record layer subtree header */
     ti = proto_tree_add_item(tree, hf_ssl2_record, tvb, initial_offset,
@@ -1674,25 +1767,53 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     /* if we get a server_hello or later handshake in v2, then set
      * this to sslv2
      */
-    if (*conv_version == SSL_VER_UNKNOWN
-        && msg_type >= 2 && msg_type <= 8)
+    if (*conv_version == SSL_VER_UNKNOWN)
+    {
+        if (ssl_looks_like_valid_pct_handshake(tvb,
+                                               (initial_offset +
+                                                record_length_length),
+                                               record_length)) {
+            *conv_version = SSL_VER_PCT;
+            ssl_set_conv_version(pinfo, *conv_version);
+        }
+        else if (msg_type >= 2 && msg_type <= 8)
+        {
+            *conv_version = SSL_VER_SSLv2;
+            ssl_set_conv_version(pinfo, *conv_version);
+        }
+    }
+
+    /* if we get here, but don't have a version set for the
+     * conversation, then set a version for just this frame
+     * (e.g., on a client hello)
+     */
+    if (check_col(pinfo->cinfo, COL_PROTOCOL))
     {
-        *conv_version = SSL_VER_SSLv2;
-        ssl_set_conv_version(pinfo, *conv_version);
+        col_set_str(pinfo->cinfo, COL_PROTOCOL,
+                    (*conv_version == SSL_VER_PCT) ? "PCT" : "SSLv2");
     }
 
     /* see if the msg_type is valid; if not the payload is
      * probably encrypted, so note that fact and bail
      */
-    msg_type_str = match_strval(msg_type, ssl_20_msg_types);
+    msg_type_str = match_strval(msg_type,
+                                (*conv_version == SSL_VER_PCT)
+                               ? pct_msg_types : ssl_20_msg_types);
     if (!msg_type_str
-        || !ssl_looks_like_valid_v2_handshake(tvb, initial_offset
-                                              + record_length_length,
-                                              record_length))
+        || ((*conv_version != SSL_VER_PCT) &&
+           !ssl_looks_like_valid_v2_handshake(tvb, initial_offset
+                                              + record_length_length,
+                                              record_length))
+       || ((*conv_version == SSL_VER_PCT) &&
+           !ssl_looks_like_valid_pct_handshake(tvb, initial_offset
+                                               + record_length_length,
+                                               record_length)))
     {
         if (ssl_record_tree)
         {
-            proto_item_set_text(ssl_record_tree, "SSLv2 Record Layer: %s",
+            proto_item_set_text(ssl_record_tree, "%s Record Layer: %s",
+                                (*conv_version == SSL_VER_PCT)
+                                ? "PCT" : "SSLv2",
                                 "Encrypted Data");
         }
         if (check_col(pinfo->cinfo, COL_INFO))
@@ -1706,7 +1827,9 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
         if (ssl_record_tree)
         {
-            proto_item_set_text(ssl_record_tree, "SSLv2 Record Layer: %s",
+            proto_item_set_text(ssl_record_tree, "%s Record Layer: %s",
+                                (*conv_version == SSL_VER_PCT)
+                                ? "PCT" : "SSLv2",
                                 msg_type_str);
         }
     }
@@ -1746,40 +1869,58 @@ dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     /* add the message type */
     if (ssl_record_tree)
     {
-        proto_tree_add_item(ssl_record_tree, hf_ssl2_msg_type, tvb,
-                            offset, 1, 0);
+        proto_tree_add_item(ssl_record_tree,
+                            (*conv_version == SSL_VER_PCT)
+                            ? hf_pct_msg_type : hf_ssl2_msg_type,
+                            tvb, offset, 1, 0);
     }
     offset++;                   /* move past msg_type byte */
 
+    if (*conv_version != SSL_VER_PCT)
+    {
+        /* dissect the message (only handle client hello right now) */
+        switch (msg_type) {
+        case SSL2_HND_CLIENT_HELLO:
+            dissect_ssl2_hnd_client_hello(tvb, ssl_record_tree, offset);
+            break;
 
-    /* dissect the message (only handle client hello right now) */
-    switch (msg_type) {
-    case SSL2_HND_CLIENT_HELLO:
-        dissect_ssl2_hnd_client_hello(tvb, ssl_record_tree, offset);
-        break;
-
-    case SSL2_HND_CLIENT_MASTER_KEY:
-        dissect_ssl2_hnd_client_master_key(tvb, ssl_record_tree, offset);
-        break;
+        case SSL2_HND_CLIENT_MASTER_KEY:
+            dissect_ssl2_hnd_client_master_key(tvb, ssl_record_tree, offset);
+            break;
 
-    case SSL2_HND_SERVER_HELLO:
-        dissect_ssl2_hnd_server_hello(tvb, ssl_record_tree, offset);
-        break;
+        case SSL2_HND_SERVER_HELLO:
+            dissect_ssl2_hnd_server_hello(tvb, ssl_record_tree, offset);
+            break;
 
-    case SSL2_HND_ERROR:
-    case SSL2_HND_CLIENT_FINISHED:
-    case SSL2_HND_SERVER_VERIFY:
-    case SSL2_HND_SERVER_FINISHED:
-    case SSL2_HND_REQUEST_CERTIFICATE:
-    case SSL2_HND_CLIENT_CERTIFICATE:
-        /* unimplemented */
-        break;
+        case SSL2_HND_ERROR:
+        case SSL2_HND_CLIENT_FINISHED:
+        case SSL2_HND_SERVER_VERIFY:
+        case SSL2_HND_SERVER_FINISHED:
+        case SSL2_HND_REQUEST_CERTIFICATE:
+        case SSL2_HND_CLIENT_CERTIFICATE:
+            /* unimplemented */
+            break;
 
-    default:                    /* unknown */
-        break;
+        default:                    /* unknown */
+            break;
+        }
     }
+    else
+    {
+        /* dissect the message */
+        switch (msg_type) {
+        case PCT_MSG_CLIENT_HELLO:
+        case PCT_MSG_SERVER_HELLO:
+        case PCT_MSG_CLIENT_MASTER_KEY:
+        case PCT_MSG_SERVER_VERIFY:
+        case PCT_MSG_ERROR:
+            /* unimplemented */
+            break;
 
-
+        default:                    /* unknown */
+            break;
+        }
+    }
     return (initial_offset + record_length_length + record_length);
 }
 
@@ -2046,7 +2187,7 @@ dissect_ssl2_hnd_server_hello(tvbuff_t *tvb,
     if (cipher_spec_length > 0)
     {
         /* provide a collapsing node for the cipher specs */
-        ti = proto_tree_add_none_format(tree, 
+        ti = proto_tree_add_none_format(tree,
                                         hf_ssl_handshake_cipher_suites,
                                         tvb, offset, cipher_spec_length,
                                         "Cipher Specs (%u spec%s)",
@@ -2114,7 +2255,7 @@ ssl_set_conv_version(packet_info *pinfo, guint version)
         /* get rid of the current data */
         conversation_delete_proto_data(conversation, proto_ssl);
     }
-    conversation_add_proto_data(conversation, proto_ssl, (void *)version);
+    conversation_add_proto_data(conversation, proto_ssl, GINT_TO_POINTER(version));
 }
 
 static int
@@ -2226,6 +2367,8 @@ ssl_looks_like_sslv2(tvbuff_t *tvb, guint32 offset)
     case SSL2_HND_CLIENT_HELLO:
     case SSL2_HND_CLIENT_MASTER_KEY:
     case SSL2_HND_SERVER_HELLO:
+    case PCT_MSG_CLIENT_MASTER_KEY:
+    case PCT_MSG_ERROR:
         return 1;
     }
     return 0;
@@ -2323,6 +2466,78 @@ ssl_looks_like_valid_v2_handshake(tvbuff_t *tvb, guint32 offset,
     return 0;
 }
 
+/* applies a heuristic to determine whether
+ * or not the data beginning at offset looks
+ * like a valid, unencrypted v2 handshake message.
+ * since it isn't possible to completely tell random
+ * data apart from a valid message without state,
+ * we try to help the odds.
+ */
+static int
+ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset,
+                                  guint32 record_length)
+{
+    /* first byte should be a msg_type.
+     *
+     *   - we know we only see client_hello, client_master_key,
+     *     and server_hello in the clear, so check to see if
+     *     msg_type is one of those (this gives us a 3 in 2^8
+     *     chance of saying yes with random payload)
+     *
+     *   - for those three types that we know about, do some
+     *     further validation to reduce the chance of an error
+     */
+    guint8 msg_type;
+    guint16 version;
+    guint32 sum;
+
+    /* fetch the msg_type */
+    msg_type = tvb_get_guint8(tvb, offset);
+
+    switch (msg_type) {
+    case PCT_MSG_CLIENT_HELLO:
+        /* version follows msg byte, so verify that this is valid */
+        version = tvb_get_ntohs(tvb, offset+1);
+        return version == PCT_VERSION_1;
+        break;
+
+    case PCT_MSG_SERVER_HELLO:
+        /* version is one byte after msg_type */
+        version = tvb_get_ntohs(tvb, offset+2);
+        return version == PCT_VERSION_1;
+        break;
+
+    case PCT_MSG_CLIENT_MASTER_KEY:
+        /* sum of various length fields must be less than record length */
+        sum  = tvb_get_ntohs(tvb, offset + 6); /* clear_key_length */
+        sum += tvb_get_ntohs(tvb, offset + 8); /* encrypted_key_length */
+        sum += tvb_get_ntohs(tvb, offset + 10); /* key_arg_length */
+        sum += tvb_get_ntohs(tvb, offset + 12); /* verify_prelude_length */
+        sum += tvb_get_ntohs(tvb, offset + 14); /* client_cert_length */
+        sum += tvb_get_ntohs(tvb, offset + 16); /* response_length */
+        if (sum > record_length)
+        {
+            return 0;
+        }
+        return 1;
+        break;
+
+    case PCT_MSG_SERVER_VERIFY:
+       /* record is 36 bytes longer than response_length */
+       sum = tvb_get_ntohs(tvb, offset + 34); /* response_length */
+       if ((sum + 36) == record_length)
+           return 1;
+       else
+           return 0;
+       break;
+
+    default:
+        return 0;
+    }
+    return 0;
+}
+
+
 /*********************************************************************
  *
  * Standard Ethereal Protocol Registration and housekeeping
@@ -2349,6 +2564,11 @@ proto_register_ssl(void)
             FT_UINT8, BASE_DEC, VALS(ssl_20_msg_types), 0x0,
             "SSLv2 handshake message type", HFILL}
         },
+        { &hf_pct_msg_type,
+          { "Handshake Message Type", "ssl.pct_handshake.type",
+            FT_UINT8, BASE_DEC, VALS(pct_msg_types), 0x0,
+            "PCT handshake message type", HFILL}
+        },
         { &hf_ssl_record_version,
           { "Version", "ssl.record.version",
             FT_UINT16, BASE_HEX, VALS(ssl_versions), 0x0,
@@ -2365,9 +2585,9 @@ proto_register_ssl(void)
             "Payload is application data", HFILL }
         },
         { & hf_ssl2_record,
-          { "SSLv2 Record Header", "ssl.record",
+          { "SSLv2/PCT Record Header", "ssl.record",
             FT_NONE, BASE_DEC, NULL, 0x0,
-            "SSLv2 record data", HFILL }
+            "SSLv2/PCT record data", HFILL }
         },
         { &hf_ssl2_record_is_escape,
           { "Is Escape", "ssl.record.is_escape",
@@ -2651,7 +2871,7 @@ proto_register_ssl(void)
                                      "When enabled, SSL records that span multiple TCP segments are desegmented",
                                      &ssl_desegment);
     }
-  
+
     register_dissector("ssl", dissect_ssl, proto_ssl);
 
 }