aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2018-07-31 21:57:42 -0700
committerGuy Harris <guy@alum.mit.edu>2018-08-01 04:58:43 +0000
commit940775b9486091ade014396f65ca84f731b38cf8 (patch)
tree13f6ff8076f576570a58b400f27e9017f9d1d6d1 /wiretap
parent9cf292a30f0098c9abcef57d9242cbc2d00e5075 (diff)
Do most of the RFC 7468 file processing in the dissector.
Have the Wiretap code just do a heuristic test to see if the file looks like a RFC 7468 file and just had the entire blob of raw file data to the caller, with an encapsulation type of WTAP_ENCAP_RFC7468. Have a file-rfc7468.c dissector that processes the lines of the file, displaying all of them. Have it extract the label from the pre-encapsulation boundary line, and, after it's decoded the base64-encoded data lines into a blob of data, try handing the tvbuff with the blob to dissectors that have registered in the "pem.preeb_label" dissector table with the appropriate label value, and hand it to the raw BER dissector only if that fails. This allows some files to have the content dissected as more than just a raw blob of BER-encoded data. Change-Id: I98db9f0beb86e5694fb8e886005a2df4fc96ba71 Reviewed-on: https://code.wireshark.org/review/28914 Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'wiretap')
-rw-r--r--wiretap/pem.c192
-rw-r--r--wiretap/wtap.c3
-rw-r--r--wiretap/wtap.h1
3 files changed, 80 insertions, 116 deletions
diff --git a/wiretap/pem.c b/wiretap/pem.c
index c14f8b89f3..d0b7b66e46 100644
--- a/wiretap/pem.c
+++ b/wiretap/pem.c
@@ -18,22 +18,45 @@
#include <string.h>
+static gboolean pem_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info)
+{
+ gint64 file_size;
+ int packet_size;
+
+ if ((file_size = wtap_file_size(wth, err)) == -1)
+ return FALSE;
+
+ if (file_size > G_MAXINT) {
+ /*
+ * Probably a corrupt capture file; don't blow up trying
+ * to allocate space for an immensely-large packet.
+ */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pem: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
+ file_size, G_MAXINT);
+ return FALSE;
+ }
+ packet_size = (int)file_size;
+
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
+
+ rec->rec_header.packet_header.caplen = packet_size;
+ rec->rec_header.packet_header.len = packet_size;
+
+ rec->ts.secs = 0;
+ rec->ts.nsecs = 0;
+
+ return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
+}
+
/* 128 bytes should be enough to contain any line. Strictly speaking, 64 is
enough, but we provide some leeway to accomodate nonconformant producers and
trailing whitespace. The 2 extra bytes are for the trailing newline and NUL
terminator. */
#define MAX_LINE_LENGTH (128 + 2)
-/* based on the `label` production in RFC 7468 */
-#define RE_LABEL "([!-,.-~]([-\\s]?[!-,.-~])*)?"
-
-struct pem_priv {
- GRegex *re_blank_line;
- GRegex *re_pre_eb;
- GRegex *re_post_eb;
- GRegex *re_base64;
-};
-
static char *read_complete_text_line(char line[MAX_LINE_LENGTH], FILE_T fh, int *err, gchar **err_info)
{
char *line_end;
@@ -58,146 +81,83 @@ static char *read_complete_text_line(char line[MAX_LINE_LENGTH], FILE_T fh, int
return line_end;
}
-static gboolean pem_read_value(wtap *wth, FILE_T fh, wtap_rec *rec,
- Buffer *buf, int *err, gchar **err_info)
+static gboolean pem_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
{
- struct pem_priv *priv = (struct pem_priv *)wth->priv;
+ gint64 offset;
- char line[MAX_LINE_LENGTH];
+ *err = 0;
- // skip blank lines
- do {
- if (!read_complete_text_line(line, fh, err, err_info)) return FALSE;
- } while (g_regex_match(priv->re_blank_line, line, (GRegexMatchFlags)0, NULL));
+ offset = file_tell(wth->fh);
- if (!g_regex_match(priv->re_pre_eb, line, (GRegexMatchFlags)0, NULL)) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup("invalid pre-encapsulation boundary");
+ /* there is only ever one packet */
+ if (offset != 0)
return FALSE;
- }
-
- gint base64_state = 0;
- guint base64_save = 0;
- ws_buffer_clean(buf);
-
- for (; ; ) {
- char *line_end = read_complete_text_line(line, fh, err, err_info);
- if (!line_end) {
- if (*err == 0) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup("missing post-encapsulation boundary");
- }
- return FALSE;
- }
-
- if (g_regex_match(priv->re_post_eb, line, (GRegexMatchFlags)0, NULL))
- break;
-
- if (!g_regex_match(priv->re_base64, line, (GRegexMatchFlags)0, NULL)) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup("invalid base64 line");
- return FALSE;
- }
-
- guchar decoded[(sizeof(line) / 4) * 3 + 3];
- guint32 decoded_size = (guint32) g_base64_decode_step(
- line, line_end - line, decoded, &base64_state, &base64_save);
-
- if ((guint32)ws_buffer_length(buf) > G_MAXUINT32 - decoded_size) {
- // we can't set the packet length if this happens
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup("encoded value too large");
- return FALSE;
- }
+ *data_offset = offset;
- ws_buffer_append(buf, decoded, decoded_size);
- }
-
- rec->rec_type = REC_TYPE_PACKET;
- rec->presence_flags = 0;
- rec->rec_header.packet_header.len =
- rec->rec_header.packet_header.caplen =
- (guint32)ws_buffer_length(buf);
-
- return TRUE;
-}
-
-static gboolean pem_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
-{
- *data_offset = file_tell(wth->fh);
-
- return pem_read_value(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
+ return pem_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
}
static gboolean pem_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
Buffer *buf, int *err, gchar **err_info)
{
+ /* there is only one packet */
+ if (seek_off > 0) {
+ *err = 0;
+ return FALSE;
+ }
+
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
- return pem_read_value(wth, wth->random_fh, rec, buf, err, err_info);
+ return pem_read_file(wth, wth->random_fh, rec, buf, err, err_info);
}
-static void pem_close(wtap *wth)
-{
- struct pem_priv *priv = (struct pem_priv *)wth->priv;
-
- g_regex_unref(priv->re_blank_line);
- g_regex_unref(priv->re_pre_eb);
- g_regex_unref(priv->re_post_eb);
- g_regex_unref(priv->re_base64);
-}
+//
+// Arbitrary value - we don't want to read all of a huge non-PEM file
+// only to find no pre-encapsulation boundary.
+//
+#define MAX_EXPLANATORY_TEXT_LINES 20
wtap_open_return_val pem_open(wtap *wth, int *err, gchar **err_info)
{
- static const char expected_magic[] = "-----BEGIN ";
- char actual_magic[sizeof(expected_magic) - 1];
+ gboolean found_preeb;
+ static const char preeb_begin[] = "-----BEGIN ";
+ char line[MAX_LINE_LENGTH];
- if (!wtap_read_bytes(wth->fh, &actual_magic, sizeof(actual_magic), err, err_info)) {
- if (*err == WTAP_ERR_SHORT_READ)
- return WTAP_OPEN_NOT_MINE;
- return WTAP_OPEN_ERROR;
- }
+ //
+ // Skip up to MAX_EXPLANATORY_TEXT_LINES worth of lines that don't
+ // look like pre-encapsulation boundaries.
+ //
+ found_preeb = FALSE;
+ for (unsigned int i = 0; i < MAX_EXPLANATORY_TEXT_LINES; i++) {
+ if (!read_complete_text_line(line, wth->fh, err, err_info)) {
+ if (*err == WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_NOT_MINE;
+ return WTAP_OPEN_ERROR;
+ }
- if (memcmp(expected_magic, actual_magic, sizeof(actual_magic)) != 0)
+ // Does the line look like a pre-encapsulation boundary?
+ if (memcmp(line, preeb_begin, sizeof preeb_begin - 1) == 0) {
+ // Yes.
+ found_preeb = TRUE;
+ break;
+ }
+ }
+ if (!found_preeb)
return WTAP_OPEN_NOT_MINE;
if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
return WTAP_OPEN_ERROR;
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PEM;
- wth->file_encap = WTAP_ENCAP_BER;
+ wth->file_encap = WTAP_ENCAP_RFC7468;
wth->snapshot_length = 0;
wth->file_tsprec = WTAP_TSPREC_SEC;
- struct pem_priv *priv = g_new0(struct pem_priv, 1);
-
- priv->re_blank_line = g_regex_new("^\\s*$", G_REGEX_RAW, (GRegexMatchFlags)0, NULL);
-
- priv->re_pre_eb = g_regex_new("^-----BEGIN " RE_LABEL "-----\\s*$",
- (GRegexCompileFlags)(G_REGEX_RAW | G_REGEX_NO_AUTO_CAPTURE),
- (GRegexMatchFlags)0, NULL);
- priv->re_post_eb = g_regex_new("^-----END " RE_LABEL "-----\\s*$",
- (GRegexCompileFlags)(G_REGEX_RAW | G_REGEX_NO_AUTO_CAPTURE),
- (GRegexMatchFlags)0, NULL);
-
- priv->re_base64 = g_regex_new("^[\\sA-Za-z0-9+/]*(=\\s*(=\\s*)?)?$",
- (GRegexCompileFlags)(G_REGEX_RAW | G_REGEX_NO_AUTO_CAPTURE),
- (GRegexMatchFlags)0, NULL);
-
- wth->priv = priv;
-
wth->subtype_read = pem_read;
wth->subtype_seek_read = pem_seek_read;
- wth->subtype_close = pem_close;
-
- if (!priv->re_blank_line || !priv->re_pre_eb || !priv->re_post_eb || !priv->re_base64) {
- *err = WTAP_ERR_INTERNAL;
- *err_info = g_strdup("failed to initialize reader");
- return WTAP_OPEN_ERROR;
- }
return WTAP_OPEN_MINE;
}
diff --git a/wiretap/wtap.c b/wiretap/wtap.c
index 1aa672693a..de5ab7192b 100644
--- a/wiretap/wtap.c
+++ b/wiretap/wtap.c
@@ -920,6 +920,9 @@ static struct encap_type_info encap_table_base[] = {
/* WTAP_ENCAP_RUBY_MARSHAL */
{ "Ruby marshal object", "ruby_marshal" },
+
+ /* WTAP_ENCAP_RFC7468 */
+ { "RFC 7468 file", "rfc7468" },
};
WS_DLL_LOCAL
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index d1beb85dfe..410001dddd 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -282,6 +282,7 @@ extern "C" {
#define WTAP_ENCAP_DOCSIS31_XRA31 199
#define WTAP_ENCAP_DPAUXMON 200
#define WTAP_ENCAP_RUBY_MARSHAL 201
+#define WTAP_ENCAP_RFC7468 202
/* After adding new item here, please also add new item to encap_table_base array */