summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/file-rfc7468.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/file-rfc7468.c')
-rw-r--r--epan/dissectors/file-rfc7468.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/epan/dissectors/file-rfc7468.c b/epan/dissectors/file-rfc7468.c
new file mode 100644
index 00000000..85c43972
--- /dev/null
+++ b/epan/dissectors/file-rfc7468.c
@@ -0,0 +1,489 @@
+/* file-rfc7468.c
+ * Routines for dissection of files in the format specified by RFC 7468.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <wiretap/wtap.h>
+
+void proto_register_rfc7468(void);
+void proto_reg_handoff_rfc7468(void);
+
+static int proto_rfc7468 = -1;
+
+static gint ett_rfc7468 = -1;
+static gint ett_rfc7468_preeb = -1;
+static gint ett_rfc7468_data = -1;
+static gint ett_rfc7468_posteb = -1;
+
+static int hf_rfc7468_preeb_label = -1;
+static int hf_rfc7468_ber_data = -1;
+static int hf_rfc7468_posteb_label = -1;
+
+static dissector_handle_t rfc7468_handle = NULL;
+static dissector_handle_t ber_handle = NULL;
+
+static dissector_table_t rfc7468_label_table;
+
+static gboolean
+line_is_eb(const guchar *line, int linelen, const char *prefix,
+ size_t prefixlen, const guchar **labelpp, int *labellenp)
+{
+ static const char suffix[] = "-----";
+#define suffixlen (sizeof suffix - 1)
+ const guchar *labelp;
+ int labellen;
+
+ /*
+ * Is this line an encapulation boundary of the type specified by the
+ * prefix?
+ *
+ * First, it must be big enough to include the prefix at the beginning
+ * and the suffix at the end.
+ */
+ if ((size_t)linelen < prefixlen + suffixlen) {
+ /*
+ * No - it's too short.
+ */
+ return FALSE;
+ }
+
+ /*
+ * It is, but it must begin with the prefix.
+ */
+ if (memcmp(line, prefix, prefixlen) != 0) {
+ /*
+ * No - it doesn't begin with the prefix.
+ */
+ return FALSE;
+ }
+
+ /*
+ * It does, but it must also end with the suffix.
+ */
+ if (memcmp(line + linelen - suffixlen, suffix, suffixlen) != 0) {
+ /*
+ * No - it doesn't end with the suffix.
+ */
+ return FALSE;
+ }
+
+ /*
+ * It begins with the prefix and ends with the suffix. Check
+ * the label, if there is one.
+ */
+ labelp = line + prefixlen;
+ labellen = (int)(linelen - (prefixlen + suffixlen));
+ *labelpp = labelp;
+ *labellenp = labellen;
+ if (labellen == 0) {
+ /* The label is empty. */
+ return TRUE;
+ }
+
+ /*
+ * The first character of the label must be 0x21-0x2C or 0x2E-0x7F,
+ * i.e., printable ASCII other than SP or '-'.
+ */
+ if (*labelp == ' ' || *labelp == '-')
+ return FALSE;
+ labelp++;
+ labellen--;
+
+ /*
+ * The rest of the characters must be printable ASCII.
+ */
+ for (int i = 0; i < labellen; i++, labelp++) {
+ if (*labelp < 0x20 || *labelp > 0x7E) {
+ /* Not printable ASCII. */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+line_is_blank(const guchar *line, int linelen)
+{
+ const guchar *p;
+
+ p = line;
+ for (int i = 0; i < linelen; i++, p++) {
+ if (*p != ' ' && *p != '\t') {
+ /* Not space or tab */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static const char preeb_prefix[] = "-----BEGIN ";
+#define preeb_prefix_len (sizeof preeb_prefix - 1)
+static const char posteb_prefix[] = "-----END ";
+#define posteb_prefix_len (sizeof posteb_prefix - 1)
+
+static gint
+dissect_rfc7468(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int offset;
+ int linelen;
+ int next_offset = 0;
+ const guchar *line;
+ const guchar *labelp = NULL;
+ int labellen = 0;
+ char *label;
+ proto_tree *rfc7468_tree, *preeb_tree, *posteb_tree;
+ proto_item *rfc7468_item, *ti;
+
+ offset = 0;
+ rfc7468_item = proto_tree_add_item(tree, proto_rfc7468, tvb, offset, -1, ENC_NA);
+ rfc7468_tree = proto_item_add_subtree(rfc7468_item, ett_rfc7468);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "rfc7468");
+
+ /*
+ * First, process the text lines prior to the pre-encapsulation
+ * boundary; they're explanatory text lines.
+ */
+ while (tvb_offset_exists(tvb, offset)) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /* No complete line was found. Nothing more to do. */
+ return tvb_captured_length(tvb);
+ }
+
+ /*
+ * Get a buffer that refers to the line.
+ *
+ * Note that "tvb_find_line_end()" will return a value that
+ * is not longer than what's in the buffer, so the
+ * "tvb_get_ptr()" call won't throw an exception.
+ */
+ line = tvb_get_ptr(tvb, offset, linelen);
+
+ /*
+ * Is this line a pre-encapulation boundary?
+ */
+ if (line_is_eb(line, linelen, preeb_prefix, sizeof preeb_prefix - 1,
+ &labelp, &labellen)) {
+ /*
+ * Yes - we're finished with the explanatory text lines.
+ */
+ break;
+ }
+
+ /*
+ * Add this line to the dissection.
+ */
+ proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+ }
+
+ /*
+ * This line is the pre-encapsulation boundary.
+ * Put it into the protocol tree, and create a subtree under it.
+ */
+ ti = proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
+ preeb_tree = proto_item_add_subtree(ti, ett_rfc7468_preeb);
+
+ /*
+ * Extract the label, and put it in that subtree.
+ */
+ label = wmem_strndup(pinfo->pool, labelp, labellen);
+ proto_tree_add_item(preeb_tree, hf_rfc7468_preeb_label, tvb,
+ offset + (int)preeb_prefix_len, labellen, ENC_ASCII);
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Label: %s", label);
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+
+ /*
+ * Skip over any blank lines before the base64 information.
+ */
+ while (tvb_offset_exists(tvb, offset)) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /* No complete line was found. We're done. */
+ return tvb_captured_length(tvb);
+ }
+
+ /*
+ * Get a buffer that refers to the line.
+ *
+ * Note that "tvb_find_line_end()" will return a value that
+ * is not longer than what's in the buffer, so the
+ * "tvb_get_ptr()" call won't throw an exception.
+ */
+ line = tvb_get_ptr(tvb, offset, linelen);
+
+ /*
+ * Is the line entirely blank (space or tab)?
+ */
+ if (!line_is_blank(line, linelen)) {
+ /*
+ * No.
+ */
+ break;
+ }
+
+ /*
+ * Add this line to the dissection.
+ */
+ proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+ }
+
+ /*
+ * OK, this should be base64-encoded binary data.
+ */
+ guint8 *databuf = NULL;
+ gsize databufsize = 0;
+ gint base64_state = 0;
+ guint base64_save = 0;
+ guint datasize = 0;
+ while (tvb_offset_exists(tvb, offset)) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /*
+ * No complete line was found. Nothing more to do.
+ */
+ return tvb_captured_length(tvb);
+ }
+
+ /*
+ * Get a buffer that refers to the line.
+ *
+ * Note that "tvb_find_line_end()" will return a value that
+ * is not longer than what's in the buffer, so the
+ * "tvb_get_ptr()" call won't throw an exception.
+ */
+ line = tvb_get_ptr(tvb, offset, linelen);
+
+ /*
+ * Is this line a post-encapulation boundary?
+ */
+ if (line_is_eb(line, linelen, posteb_prefix, sizeof posteb_prefix - 1,
+ &labelp, &labellen)) {
+ /*
+ * Yes - we're done with the base64 data.
+ */
+ break;
+ }
+
+ /*
+ * Add this line to the dissection.
+ */
+ proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
+
+ /*
+ * Decode it and add that to the buffer.
+ * First, grow the buffer as needed.
+ */
+ databufsize += (linelen / 4) * 3 + 3;
+ databuf = (guint8 *)wmem_realloc(pinfo->pool, databuf, databufsize);
+
+ /*
+ * Now decode into it.
+ */
+ guint decodesize = (guint)g_base64_decode_step(line, linelen,
+ &databuf[datasize],
+ &base64_state,
+ &base64_save);
+ datasize += decodesize;
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+ }
+
+ /*
+ * Make a tvbuff for the data, and put it into the protocol tree,
+ * if we have any.
+ */
+ if (datasize != 0) {
+ tvbuff_t *data_tvb;
+
+ data_tvb = tvb_new_child_real_data(tvb, databuf, datasize, datasize);
+ add_new_data_source(pinfo, data_tvb, "Base64-encoded data");
+
+ /*
+ * Try to decode it based on the label.
+ */
+ if (dissector_try_string(rfc7468_label_table, label, data_tvb, pinfo,
+ tree, NULL) == 0) {
+ proto_tree *data_tree;
+
+ /*
+ * No known dissector; decode it as BER.
+ */
+ ti = proto_tree_add_item(tree, hf_rfc7468_ber_data, data_tvb, 0, -1, ENC_NA);
+ data_tree = proto_item_add_subtree(ti, ett_rfc7468_data);
+ call_dissector(ber_handle, data_tvb, pinfo, data_tree);
+ }
+ }
+
+ /*
+ * This line is the post-encapsulation boundary.
+ * Put it into the protocol tree, and create a subtree under it.
+ */
+ ti = proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
+ posteb_tree = proto_item_add_subtree(ti, ett_rfc7468_posteb);
+
+ /*
+ * Extract the label, and put it in that subtree.
+ */
+ proto_tree_add_item(posteb_tree, hf_rfc7468_posteb_label, tvb,
+ offset + (int)posteb_prefix_len, labellen, ENC_ASCII);
+
+ return tvb_captured_length(tvb);
+}
+
+//
+// Arbitrary value - we don't want to read all of a huge non-RFC 7468 file
+// only to find no pre-encapsulation boundary.
+//
+#define MAX_EXPLANATORY_TEXT_LINES 20
+
+static gboolean
+dissect_rfc7468_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ int offset;
+ int linelen;
+ int next_offset;
+ const guchar *line;
+ const guchar *labelp;
+ int labellen;
+ gboolean found = FALSE;
+
+ /*
+ * Look for a pre-encapsulation boundary.
+ * Process up to MAX_EXPLANATORY_TEXT_LINES worth of lines that don't
+ * look like pre-encapsulation boundaries.
+ */
+ offset = 0;
+ for (unsigned int i = 0; i < MAX_EXPLANATORY_TEXT_LINES; i++) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /*
+ * No complete line was found; we ran out of file data
+ * and didn't find a pre-encapsulation boundary, so this
+ * isn't an RFC 7468 file.
+ */
+ break;
+ }
+
+ /*
+ * Get a buffer that refers to the line.
+ *
+ * Note that "tvb_find_line_end()" will return a value that
+ * is not longer than what's in the buffer, so the
+ * "tvb_get_ptr()" call won't throw an exception.
+ */
+ line = tvb_get_ptr(tvb, offset, linelen);
+
+ /*
+ * Is this line a pre-encapulation boundary?
+ */
+ if (line_is_eb(line, linelen, preeb_prefix, sizeof preeb_prefix - 1,
+ &labelp, &labellen)) {
+ /*
+ * Yes - we're done looking.
+ */
+ found = TRUE;
+ break;
+ }
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+ }
+
+ /*
+ * Did we find a pre-encapsulation boundary?
+ */
+ if (!found)
+ return FALSE; /* no */
+
+ /*
+ * OK, it's an RFC 7468 file. Dissect it.
+ */
+ dissect_rfc7468(tvb, pinfo, tree, data);
+ return TRUE;
+}
+
+void
+proto_register_rfc7468(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_rfc7468_preeb_label,
+ { "Pre-encapsulation boundary label", "rfc7468.preeb_label", FT_STRING, BASE_NONE,
+ NULL, 0, NULL, HFILL } },
+ { &hf_rfc7468_ber_data,
+ { "BER data", "rfc7468.ber_data", FT_NONE, BASE_NONE,
+ NULL, 0, NULL, HFILL } },
+ { &hf_rfc7468_posteb_label,
+ { "Post-encapsulation boundary label", "rfc7468.posteb_label", FT_STRING, BASE_NONE,
+ NULL, 0, NULL, HFILL } },
+ };
+
+ static gint *ett[] = {
+ &ett_rfc7468,
+ &ett_rfc7468_preeb,
+ &ett_rfc7468_data,
+ &ett_rfc7468_posteb
+ };
+
+ proto_rfc7468 = proto_register_protocol("RFC 7468 file format", "rfc7468", "rfc7468");
+
+ proto_register_field_array(proto_rfc7468, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ rfc7468_label_table = register_dissector_table("rfc7468.preeb_label", "FFF",
+ proto_rfc7468, FT_STRING,
+ STRING_CASE_INSENSITIVE);
+
+ rfc7468_handle = register_dissector("rfc7468", dissect_rfc7468, proto_rfc7468);
+}
+
+void
+proto_reg_handoff_rfc7468(void)
+{
+ heur_dissector_add("wtap_file", dissect_rfc7468_heur, "RFC 7468 file", "rfc7468_wtap", proto_rfc7468, HEURISTIC_ENABLE);
+ dissector_add_uint("wtap_encap", WTAP_ENCAP_RFC7468, rfc7468_handle);
+
+ ber_handle = find_dissector("ber");
+}
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */