Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / file-rfc7468.c
blobd676dfffdf7ecdca449cf168c40d47e7f5f13ed7
1 /* file-rfc7468.c
2 * Routines for dissection of files in the format specified by RFC 7468.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <epan/packet.h>
14 #include <wiretap/wtap.h>
15 #include <wsutil/array.h>
17 void proto_register_rfc7468(void);
18 void proto_reg_handoff_rfc7468(void);
20 static int proto_rfc7468;
22 static int ett_rfc7468;
23 static int ett_rfc7468_preeb;
24 static int ett_rfc7468_data;
25 static int ett_rfc7468_posteb;
27 static int hf_rfc7468_preeb_label;
28 static int hf_rfc7468_ber_data;
29 static int hf_rfc7468_posteb_label;
31 static dissector_handle_t rfc7468_handle;
32 static dissector_handle_t ber_handle;
34 static dissector_table_t rfc7468_label_table;
36 static bool
37 line_is_eb(const unsigned char *line, int linelen, const char *prefix,
38 size_t prefixlen, const unsigned char **labelpp, int *labellenp)
40 static const char suffix[] = "-----";
41 #define suffixlen (sizeof suffix - 1)
42 const unsigned char *labelp;
43 int labellen;
46 * Is this line an encapulation boundary of the type specified by the
47 * prefix?
49 * First, it must be big enough to include the prefix at the beginning
50 * and the suffix at the end.
52 if ((size_t)linelen < prefixlen + suffixlen) {
54 * No - it's too short.
56 return false;
60 * It is, but it must begin with the prefix.
62 if (memcmp(line, prefix, prefixlen) != 0) {
64 * No - it doesn't begin with the prefix.
66 return false;
70 * It does, but it must also end with the suffix.
72 if (memcmp(line + linelen - suffixlen, suffix, suffixlen) != 0) {
74 * No - it doesn't end with the suffix.
76 return false;
80 * It begins with the prefix and ends with the suffix. Check
81 * the label, if there is one.
83 labelp = line + prefixlen;
84 labellen = (int)(linelen - (prefixlen + suffixlen));
85 *labelpp = labelp;
86 *labellenp = labellen;
87 if (labellen == 0) {
88 /* The label is empty. */
89 return true;
93 * The first character of the label must be 0x21-0x2C or 0x2E-0x7F,
94 * i.e., printable ASCII other than SP or '-'.
96 if (*labelp == ' ' || *labelp == '-')
97 return false;
98 labelp++;
99 labellen--;
102 * The rest of the characters must be printable ASCII.
104 for (int i = 0; i < labellen; i++, labelp++) {
105 if (*labelp < 0x20 || *labelp > 0x7E) {
106 /* Not printable ASCII. */
107 return false;
110 return true;
113 static bool
114 line_is_blank(const unsigned char *line, int linelen)
116 const unsigned char *p;
118 p = line;
119 for (int i = 0; i < linelen; i++, p++) {
120 if (*p != ' ' && *p != '\t') {
121 /* Not space or tab */
122 return false;
125 return true;
128 static const char preeb_prefix[] = "-----BEGIN ";
129 #define preeb_prefix_len (sizeof preeb_prefix - 1)
130 static const char posteb_prefix[] = "-----END ";
131 #define posteb_prefix_len (sizeof posteb_prefix - 1)
133 static int
134 dissect_rfc7468(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
136 int offset;
137 int linelen;
138 int next_offset = 0;
139 const unsigned char *line;
140 const unsigned char *labelp = NULL;
141 int labellen = 0;
142 char *label;
143 proto_tree *rfc7468_tree, *preeb_tree, *posteb_tree;
144 proto_item *rfc7468_item, *ti;
146 offset = 0;
147 rfc7468_item = proto_tree_add_item(tree, proto_rfc7468, tvb, offset, -1, ENC_NA);
148 rfc7468_tree = proto_item_add_subtree(rfc7468_item, ett_rfc7468);
150 col_set_str(pinfo->cinfo, COL_PROTOCOL, "rfc7468");
153 * First, process the text lines prior to the pre-encapsulation
154 * boundary; they're explanatory text lines.
156 while (tvb_offset_exists(tvb, offset)) {
157 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
158 if (linelen == -1) {
159 /* No complete line was found. Nothing more to do. */
160 return tvb_captured_length(tvb);
164 * Get a buffer that refers to the line.
166 * Note that "tvb_find_line_end()" will return a value that
167 * is not longer than what's in the buffer, so the
168 * "tvb_get_ptr()" call won't throw an exception.
170 line = tvb_get_ptr(tvb, offset, linelen);
173 * Is this line a pre-encapulation boundary?
175 if (line_is_eb(line, linelen, preeb_prefix, sizeof preeb_prefix - 1,
176 &labelp, &labellen)) {
178 * Yes - we're finished with the explanatory text lines.
180 break;
184 * Add this line to the dissection.
186 proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
189 * Step to the next line.
191 offset = next_offset;
195 * This line is the pre-encapsulation boundary.
196 * Put it into the protocol tree, and create a subtree under it.
198 ti = proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
199 preeb_tree = proto_item_add_subtree(ti, ett_rfc7468_preeb);
202 * Extract the label, and put it in that subtree.
204 label = wmem_strndup(pinfo->pool, labelp, labellen);
205 proto_tree_add_item(preeb_tree, hf_rfc7468_preeb_label, tvb,
206 offset + (int)preeb_prefix_len, labellen, ENC_ASCII);
208 col_add_fstr(pinfo->cinfo, COL_INFO, "Label: %s", label);
211 * Step to the next line.
213 offset = next_offset;
216 * Skip over any blank lines before the base64 information.
218 while (tvb_offset_exists(tvb, offset)) {
219 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
220 if (linelen == -1) {
221 /* No complete line was found. We're done. */
222 return tvb_captured_length(tvb);
226 * Get a buffer that refers to the line.
228 * Note that "tvb_find_line_end()" will return a value that
229 * is not longer than what's in the buffer, so the
230 * "tvb_get_ptr()" call won't throw an exception.
232 line = tvb_get_ptr(tvb, offset, linelen);
235 * Is the line entirely blank (space or tab)?
237 if (!line_is_blank(line, linelen)) {
239 * No.
241 break;
245 * Add this line to the dissection.
247 proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
250 * Step to the next line.
252 offset = next_offset;
256 * OK, this should be base64-encoded binary data.
258 uint8_t *databuf = NULL;
259 size_t databufsize = 0;
260 int base64_state = 0;
261 unsigned base64_save = 0;
262 unsigned datasize = 0;
263 while (tvb_offset_exists(tvb, offset)) {
264 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
265 if (linelen == -1) {
267 * No complete line was found. Nothing more to do.
269 return tvb_captured_length(tvb);
273 * Get a buffer that refers to the line.
275 * Note that "tvb_find_line_end()" will return a value that
276 * is not longer than what's in the buffer, so the
277 * "tvb_get_ptr()" call won't throw an exception.
279 line = tvb_get_ptr(tvb, offset, linelen);
282 * Is this line a post-encapulation boundary?
284 if (line_is_eb(line, linelen, posteb_prefix, sizeof posteb_prefix - 1,
285 &labelp, &labellen)) {
287 * Yes - we're done with the base64 data.
289 break;
293 * Add this line to the dissection.
295 proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
298 * Decode it and add that to the buffer.
299 * First, grow the buffer as needed.
301 databufsize += (linelen / 4) * 3 + 3;
302 databuf = (uint8_t *)wmem_realloc(pinfo->pool, databuf, databufsize);
305 * Now decode into it.
307 unsigned decodesize = (unsigned)g_base64_decode_step(line, linelen,
308 &databuf[datasize],
309 &base64_state,
310 &base64_save);
311 datasize += decodesize;
314 * Step to the next line.
316 offset = next_offset;
320 * Make a tvbuff for the data, and put it into the protocol tree,
321 * if we have any.
323 if (datasize != 0) {
324 tvbuff_t *data_tvb;
326 data_tvb = tvb_new_child_real_data(tvb, databuf, datasize, datasize);
327 add_new_data_source(pinfo, data_tvb, "Base64-encoded data");
330 * Try to decode it based on the label.
332 if (dissector_try_string_with_data(rfc7468_label_table, label, data_tvb, pinfo,
333 tree, true, NULL) == 0) {
334 proto_tree *data_tree;
337 * No known dissector; decode it as BER.
339 ti = proto_tree_add_item(tree, hf_rfc7468_ber_data, data_tvb, 0, -1, ENC_NA);
340 data_tree = proto_item_add_subtree(ti, ett_rfc7468_data);
341 call_dissector(ber_handle, data_tvb, pinfo, data_tree);
346 * This line is the post-encapsulation boundary.
347 * Put it into the protocol tree, and create a subtree under it.
349 ti = proto_tree_add_format_text(rfc7468_tree, tvb, offset, next_offset - offset);
350 posteb_tree = proto_item_add_subtree(ti, ett_rfc7468_posteb);
353 * Extract the label, and put it in that subtree.
355 proto_tree_add_item(posteb_tree, hf_rfc7468_posteb_label, tvb,
356 offset + (int)posteb_prefix_len, labellen, ENC_ASCII);
358 return tvb_captured_length(tvb);
362 // Arbitrary value - we don't want to read all of a huge non-RFC 7468 file
363 // only to find no pre-encapsulation boundary.
365 #define MAX_EXPLANATORY_TEXT_LINES 20
367 static bool
368 dissect_rfc7468_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
370 int offset;
371 int linelen;
372 int next_offset;
373 const unsigned char *line;
374 const unsigned char *labelp;
375 int labellen;
376 bool found = false;
379 * Look for a pre-encapsulation boundary.
380 * Process up to MAX_EXPLANATORY_TEXT_LINES worth of lines that don't
381 * look like pre-encapsulation boundaries.
383 offset = 0;
384 for (unsigned int i = 0; i < MAX_EXPLANATORY_TEXT_LINES; i++) {
385 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
386 if (linelen == -1) {
388 * No complete line was found; we ran out of file data
389 * and didn't find a pre-encapsulation boundary, so this
390 * isn't an RFC 7468 file.
392 break;
396 * Get a buffer that refers to the line.
398 * Note that "tvb_find_line_end()" will return a value that
399 * is not longer than what's in the buffer, so the
400 * "tvb_get_ptr()" call won't throw an exception.
402 line = tvb_get_ptr(tvb, offset, linelen);
405 * Is this line a pre-encapulation boundary?
407 if (line_is_eb(line, linelen, preeb_prefix, sizeof preeb_prefix - 1,
408 &labelp, &labellen)) {
410 * Yes - we're done looking.
412 found = true;
413 break;
417 * Step to the next line.
419 offset = next_offset;
423 * Did we find a pre-encapsulation boundary?
425 if (!found)
426 return false; /* no */
429 * OK, it's an RFC 7468 file. Dissect it.
431 dissect_rfc7468(tvb, pinfo, tree, data);
432 return true;
435 void
436 proto_register_rfc7468(void)
438 static hf_register_info hf[] = {
439 { &hf_rfc7468_preeb_label,
440 { "Pre-encapsulation boundary label", "rfc7468.preeb_label", FT_STRING, BASE_NONE,
441 NULL, 0, NULL, HFILL } },
442 { &hf_rfc7468_ber_data,
443 { "BER data", "rfc7468.ber_data", FT_NONE, BASE_NONE,
444 NULL, 0, NULL, HFILL } },
445 { &hf_rfc7468_posteb_label,
446 { "Post-encapsulation boundary label", "rfc7468.posteb_label", FT_STRING, BASE_NONE,
447 NULL, 0, NULL, HFILL } },
450 static int *ett[] = {
451 &ett_rfc7468,
452 &ett_rfc7468_preeb,
453 &ett_rfc7468_data,
454 &ett_rfc7468_posteb
457 proto_rfc7468 = proto_register_protocol("RFC 7468 file format", "rfc7468", "rfc7468");
459 proto_register_field_array(proto_rfc7468, hf, array_length(hf));
460 proto_register_subtree_array(ett, array_length(ett));
462 rfc7468_label_table = register_dissector_table("rfc7468.preeb_label", "FFF",
463 proto_rfc7468, FT_STRING,
464 STRING_CASE_INSENSITIVE);
466 rfc7468_handle = register_dissector("rfc7468", dissect_rfc7468, proto_rfc7468);
469 void
470 proto_reg_handoff_rfc7468(void)
472 heur_dissector_add("wtap_file", dissect_rfc7468_heur, "RFC 7468 file", "rfc7468_wtap", proto_rfc7468, HEURISTIC_ENABLE);
473 dissector_add_uint("wtap_encap", WTAP_ENCAP_RFC7468, rfc7468_handle);
475 ber_handle = find_dissector("ber");
480 * Editor modelines - https://www.wireshark.org/tools/modelines.html
482 * Local variables:
483 * c-basic-offset: 4
484 * tab-width: 8
485 * indent-tabs-mode: nil
486 * End:
488 * vi: set shiftwidth=4 tabstop=8 expandtab:
489 * :indentSize=4:tabSize=8:noTabs=true: