aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--epan/dissectors/CMakeLists.txt1
-rw-r--r--epan/dissectors/asn1/cms/packet-cms-template.c2
-rw-r--r--epan/dissectors/asn1/x509af/packet-x509af-template.c6
-rw-r--r--epan/dissectors/file-rfc7468.c485
-rw-r--r--epan/dissectors/packet-cms.c2
-rw-r--r--epan/dissectors/packet-x509af.c6
-rw-r--r--wiretap/pem.c192
-rw-r--r--wiretap/wtap.c3
-rw-r--r--wiretap/wtap.h1
9 files changed, 578 insertions, 120 deletions
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index 08df528892..8a079fd6bf 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -622,6 +622,7 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/file-pcapng.c
${CMAKE_CURRENT_SOURCE_DIR}/file-png.c
${CMAKE_CURRENT_SOURCE_DIR}/file-rbm.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/file-rfc7468.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-2dparityfec.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-3com-njack.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-3com-xns.c
diff --git a/epan/dissectors/asn1/cms/packet-cms-template.c b/epan/dissectors/asn1/cms/packet-cms-template.c
index b03c96421b..0814f20b52 100644
--- a/epan/dissectors/asn1/cms/packet-cms-template.c
+++ b/epan/dissectors/asn1/cms/packet-cms-template.c
@@ -146,5 +146,5 @@ void proto_reg_handoff_cms(void) {
content_info_handle = create_dissector_handle (dissect_ContentInfo_PDU, proto_cms);
dissector_add_string("media_type", "application/pkcs7-mime", content_info_handle);
dissector_add_string("media_type", "application/pkcs7-signature", content_info_handle);
+ dissector_add_string("rfc7468.preeb_label", "CMS", content_info_handle);
}
-
diff --git a/epan/dissectors/asn1/x509af/packet-x509af-template.c b/epan/dissectors/asn1/x509af/packet-x509af-template.c
index f958f1747e..fe6cdefc00 100644
--- a/epan/dissectors/asn1/x509af/packet-x509af-template.c
+++ b/epan/dissectors/asn1/x509af/packet-x509af-template.c
@@ -182,5 +182,9 @@ void proto_reg_handoff_x509af(void) {
dissector_add_string("ldap.name", "arl", create_dissector_handle(dissect_CertificateList_PDU, proto_x509af));
dissector_add_string("ldap.name", "crossCertificatePair", create_dissector_handle(dissect_CertificatePair_PDU, proto_x509af));
-}
+ /* RFC 7468 files */
+ dissector_add_string("rfc7468.preeb_label", "CERTIFICATE", create_dissector_handle(dissect_x509af_Certificate_PDU, proto_x509af));
+ dissector_add_string("rfc7468.preeb_label", "X509 CRL", create_dissector_handle(dissect_CertificateList_PDU, proto_x509af));
+ dissector_add_string("rfc7468.preeb_label", "ATTRIBUTE CERTIFICATE", create_dissector_handle(dissect_AttributeCertificate_PDU, proto_x509af));
+}
diff --git a/epan/dissectors/file-rfc7468.c b/epan/dissectors/file-rfc7468.c
new file mode 100644
index 0000000000..cfdb8a1657
--- /dev/null
+++ b/epan/dissectors/file-rfc7468.c
@@ -0,0 +1,485 @@
+/* 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>
+
+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_data = -1;
+static int hf_rfc7468_posteb_label = -1;
+
+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;
+ const guchar *line;
+ const guchar *labelp;
+ int labellen;
+ 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);
+
+ /*
+ * First, process the text lines prior to the pre-encapsulation
+ * boundary; they're explanatory text lines.
+ */
+ for (;;) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /* No complete line was found. Not 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 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(wmem_packet_scope(), labelp, labellen);
+ proto_tree_add_item(preeb_tree, hf_rfc7468_preeb_label, tvb,
+ offset + preeb_prefix_len, labellen, ENC_ASCII|ENC_NA);
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+
+ /*
+ * Skip over any blank lines before the base64 information.
+ */
+ for (;;) {
+ 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;
+ for (;;) {
+ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ if (linelen == -1) {
+ /*
+ * XXX - should we just attempt to dissect what we've
+ * gotten so far?
+ */
+ 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 = g_realloc(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;
+ proto_tree *data_tree;
+
+ data_tvb = tvb_new_child_real_data(tvb, databuf, datasize, datasize);
+ add_new_data_source(pinfo, data_tvb, "Base64-encoded data");
+ ti = proto_tree_add_item(rfc7468_tree, hf_rfc7468_data, data_tvb, 0, -1, ENC_NA);
+ data_tree = proto_item_add_subtree(ti, ett_rfc7468_data);
+
+ /*
+ * Try to decode it based on the label.
+ */
+ if (dissector_try_string(rfc7468_label_table, label, data_tvb, pinfo,
+ data_tree, NULL) == 0) {
+ /*
+ * No known dissector; decode it as BER.
+ */
+ 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.
+ */
+ label = wmem_strndup(wmem_packet_scope(), labelp, labellen);
+ proto_tree_add_item(posteb_tree, hf_rfc7468_posteb_label, tvb,
+ offset + posteb_prefix_len, labellen, ENC_ASCII|ENC_NA);
+
+ 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 _U_)
+{
+ 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_data,
+ { "Data", "rfc7468.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,
+ TRUE);
+}
+
+void
+proto_reg_handoff_rfc7468(void)
+{
+ dissector_handle_t rfc7468_handle;
+
+ heur_dissector_add("wtap_file", dissect_rfc7468_heur, "RFC 7468 file", "rfc7468_wtap", proto_rfc7468, HEURISTIC_ENABLE);
+ rfc7468_handle = create_dissector_handle(dissect_rfc7468, proto_rfc7468);
+ dissector_add_uint("wtap_encap", WTAP_ENCAP_RFC7468, rfc7468_handle);
+
+ ber_handle = find_dissector("ber");
+}
+
+
+/*
+ * Editor modelines - http://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:
+ */
diff --git a/epan/dissectors/packet-cms.c b/epan/dissectors/packet-cms.c
index c62c92be44..b247c2ec68 100644
--- a/epan/dissectors/packet-cms.c
+++ b/epan/dissectors/packet-cms.c
@@ -3346,5 +3346,5 @@ void proto_reg_handoff_cms(void) {
content_info_handle = create_dissector_handle (dissect_ContentInfo_PDU, proto_cms);
dissector_add_string("media_type", "application/pkcs7-mime", content_info_handle);
dissector_add_string("media_type", "application/pkcs7-signature", content_info_handle);
+ dissector_add_string("rfc7468.preeb_label", "CMS", content_info_handle);
}
-
diff --git a/epan/dissectors/packet-x509af.c b/epan/dissectors/packet-x509af.c
index 19ff6e2240..e3cc317b58 100644
--- a/epan/dissectors/packet-x509af.c
+++ b/epan/dissectors/packet-x509af.c
@@ -1441,5 +1441,9 @@ void proto_reg_handoff_x509af(void) {
dissector_add_string("ldap.name", "arl", create_dissector_handle(dissect_CertificateList_PDU, proto_x509af));
dissector_add_string("ldap.name", "crossCertificatePair", create_dissector_handle(dissect_CertificatePair_PDU, proto_x509af));
-}
+ /* RFC 7468 files */
+ dissector_add_string("rfc7468.preeb_label", "CERTIFICATE", create_dissector_handle(dissect_x509af_Certificate_PDU, proto_x509af));
+ dissector_add_string("rfc7468.preeb_label", "X509 CRL", create_dissector_handle(dissect_CertificateList_PDU, proto_x509af));
+ dissector_add_string("rfc7468.preeb_label", "ATTRIBUTE CERTIFICATE", create_dissector_handle(dissect_AttributeCertificate_PDU, proto_x509af));
+}
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 */