2 * Routines for X.411 (X.400 Message Transfer) packet dissection
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <epan/packet.h>
30 #include <epan/prefs.h>
31 #include <epan/oids.h>
32 #include <epan/asn1.h>
33 #include <epan/expert.h>
34 #include <epan/wmem/wmem.h>
36 #include "packet-ber.h"
37 #include "packet-acse.h"
38 #include "packet-ros.h"
39 #include "packet-rtse.h"
41 #include "packet-x509af.h"
42 #include "packet-x509ce.h"
43 #include "packet-x509if.h"
44 #include "packet-x509sat.h"
46 #include "packet-p1.h"
47 #include <epan/strutil.h>
49 #define PNAME "X.411 Message Transfer Service"
53 static guint global_p1_tcp_port
= 102;
54 static dissector_handle_t tpkt_handle
;
55 static void prefs_register_p1(void); /* forward declaration for use in preferences registration */
57 /* Initialize the protocol and registered fields */
58 static int proto_p1
= -1;
59 static int proto_p3
= -1;
61 static int hf_p1_MTS_APDU_PDU
= -1;
62 static int hf_p1_MTABindArgument_PDU
= -1;
63 static int hf_p1_MTABindResult_PDU
= -1;
64 static int hf_p1_MTABindError_PDU
= -1;
66 #include "packet-p1-hf.c"
68 /* Initialize the subtree pointers */
69 static gint ett_p1
= -1;
70 static gint ett_p3
= -1;
71 static gint ett_p1_content_unknown
= -1;
72 static gint ett_p1_bilateral_information
= -1;
73 static gint ett_p1_additional_information
= -1;
74 static gint ett_p1_unknown_standard_extension
= -1;
75 static gint ett_p1_unknown_extension_attribute_type
= -1;
76 static gint ett_p1_unknown_tokendata_type
= -1;
77 #include "packet-p1-ett.c"
79 static expert_field ei_p1_unknown_extension_attribute_type
= EI_INIT
;
80 static expert_field ei_p1_unknown_standard_extension
= EI_INIT
;
81 static expert_field ei_p1_unknown_built_in_content_type
= EI_INIT
;
82 static expert_field ei_p1_unknown_tokendata_type
= EI_INIT
;
84 /* Dissector tables */
85 static dissector_table_t p1_extension_dissector_table
;
86 static dissector_table_t p1_extension_attribute_dissector_table
;
87 static dissector_table_t p1_tokendata_dissector_table
;
89 #include "packet-p1-table.c" /* operation and error codes */
91 typedef struct p1_address_ctx
{
93 const char *content_type_id
;
94 gboolean report_unknown_content_type
;
95 wmem_strbuf_t
* oraddress
;
98 static void set_do_address(asn1_ctx_t
* actx
, gboolean do_address
)
100 p1_address_ctx_t
* ctx
;
102 if (actx
->subtree
.tree_ctx
== NULL
) {
103 actx
->subtree
.tree_ctx
= wmem_new0(wmem_packet_scope(), p1_address_ctx_t
);
106 ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
107 ctx
->do_address
= do_address
;
110 static void do_address(const char* addr
, tvbuff_t
* tvb_string
, asn1_ctx_t
* actx
)
112 p1_address_ctx_t
* ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
114 if (ctx
&& ctx
->do_address
) {
116 wmem_strbuf_append(ctx
->oraddress
, addr
);
119 wmem_strbuf_append(ctx
->oraddress
, tvb_format_text(tvb_string
, 0, tvb_length(tvb_string
)));
125 static void do_address_str(const char* addr
, tvbuff_t
* tvb_string
, asn1_ctx_t
* actx
)
127 wmem_strbuf_t
*ddatype
= (wmem_strbuf_t
*)actx
->value_ptr
;
128 p1_address_ctx_t
* ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
130 do_address(addr
, tvb_string
, actx
);
132 if (ctx
&& ctx
->do_address
&& ddatype
&& tvb_string
)
133 wmem_strbuf_append(ddatype
, tvb_format_text(tvb_string
, 0, tvb_length(tvb_string
)));
136 static void do_address_str_tree(const char* addr
, tvbuff_t
* tvb_string
, asn1_ctx_t
* actx
, proto_tree
* tree
)
138 wmem_strbuf_t
*ddatype
= (wmem_strbuf_t
*)actx
->value_ptr
;
139 p1_address_ctx_t
* ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
141 do_address(addr
, tvb_string
, actx
);
143 if (ctx
&& ctx
->do_address
&& tvb_string
&& ddatype
) {
144 if (wmem_strbuf_get_len(ddatype
) > 0) {
145 proto_item_append_text (tree
, " (%s=%s)", wmem_strbuf_get_str(ddatype
), tvb_format_text(tvb_string
, 0, tvb_length(tvb_string
)));
150 #include "packet-p1-fn.c"
152 #include "packet-p1-table11.c" /* operation argument/result dissectors */
153 #include "packet-p1-table21.c" /* error dissector */
155 static const ros_info_t p3_ros_info
= {
159 p3_opr_code_string_vals
,
161 p3_err_code_string_vals
,
165 void p1_initialize_content_globals (asn1_ctx_t
* actx
, proto_tree
*tree
, gboolean report_unknown_cont_type
)
167 p1_address_ctx_t
* ctx
;
169 if (actx
->subtree
.tree_ctx
== NULL
) {
170 actx
->subtree
.tree_ctx
= wmem_new0(wmem_packet_scope(), p1_address_ctx_t
);
173 ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
175 actx
->subtree
.top_tree
= tree
;
176 actx
->external
.direct_reference
= NULL
;
177 ctx
->content_type_id
= NULL
;
178 ctx
->report_unknown_content_type
= report_unknown_cont_type
;
181 const char* p1_get_last_oraddress (asn1_ctx_t
* actx
)
183 p1_address_ctx_t
* ctx
;
185 if ((actx
== NULL
) || (actx
->subtree
.tree_ctx
== NULL
))
188 ctx
= (p1_address_ctx_t
*)actx
->subtree
.tree_ctx
;
189 if (wmem_strbuf_get_len(ctx
->oraddress
) <= 0)
192 return wmem_strbuf_get_str(ctx
->oraddress
);
196 * Dissect P1 MTS APDU
199 dissect_p1_mts_apdu (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
)
201 proto_item
*item
=NULL
;
202 proto_tree
*tree
=NULL
;
204 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, TRUE
, pinfo
);
206 /* save parent_tree so subdissectors can create new top nodes */
207 p1_initialize_content_globals (&asn1_ctx
, parent_tree
, TRUE
);
210 item
= proto_tree_add_item(parent_tree
, proto_p1
, tvb
, 0, -1, ENC_NA
);
211 tree
= proto_item_add_subtree(item
, ett_p1
);
214 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "P1");
215 col_set_str(pinfo
->cinfo
, COL_INFO
, "Transfer");
217 dissect_p1_MTS_APDU (FALSE
, tvb
, 0, &asn1_ctx
, tree
, hf_p1_MTS_APDU_PDU
);
218 p1_initialize_content_globals (&asn1_ctx
, NULL
, FALSE
);
222 * Dissect P1 PDUs inside a PPDU.
225 dissect_p1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
231 struct SESSION_DATA_STRUCTURE
* session
;
232 int (*p1_dissector
)(gboolean implicit_tag _U_
, tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx _U_
, proto_tree
*tree
, int hf_index _U_
) = NULL
;
233 const char *p1_op_name
;
234 int hf_p1_index
= -1;
236 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, TRUE
, pinfo
);
238 /* save parent_tree so subdissectors can create new top nodes */
239 p1_initialize_content_globals (&asn1_ctx
, parent_tree
, TRUE
);
241 /* do we have operation information from the ROS dissector? */
244 proto_tree_add_text(parent_tree
, tvb
, offset
, -1,
245 "Internal error: can't get operation information from ROS dissector.");
250 session
= ( (struct SESSION_DATA_STRUCTURE
*)data
);
252 asn1_ctx
.private_data
= session
;
254 item
= proto_tree_add_item(parent_tree
, proto_p1
, tvb
, 0, -1, ENC_NA
);
255 tree
= proto_item_add_subtree(item
, ett_p1
);
257 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "P1");
258 col_clear(pinfo
->cinfo
, COL_INFO
);
260 switch(session
->ros_op
& ROS_OP_MASK
) {
261 case (ROS_OP_BIND
| ROS_OP_ARGUMENT
): /* BindInvoke */
262 p1_dissector
= dissect_p1_MTABindArgument
;
263 p1_op_name
= "Bind-Argument";
264 hf_p1_index
= hf_p1_MTABindArgument_PDU
;
266 case (ROS_OP_BIND
| ROS_OP_RESULT
): /* BindResult */
267 p1_dissector
= dissect_p1_MTABindResult
;
268 p1_op_name
= "Bind-Result";
269 hf_p1_index
= hf_p1_MTABindResult_PDU
;
271 case (ROS_OP_BIND
| ROS_OP_ERROR
): /* BindError */
272 p1_dissector
= dissect_p1_MTABindError
;
273 p1_op_name
= "Bind-Error";
274 hf_p1_index
= hf_p1_MTABindError_PDU
;
276 case (ROS_OP_INVOKE
| ROS_OP_ARGUMENT
): /* Invoke Argument */
277 p1_dissector
= dissect_p1_MTS_APDU
;
278 p1_op_name
= "Transfer";
279 hf_p1_index
= hf_p1_MTS_APDU_PDU
;
282 proto_tree_add_text(tree
, tvb
, offset
, -1,"Unsupported P1 PDU");
283 return tvb_length(tvb
);
286 col_set_str(pinfo
->cinfo
, COL_INFO
, p1_op_name
);
288 while (tvb_reported_length_remaining(tvb
, offset
) > 0){
290 offset
=(*p1_dissector
)(FALSE
, tvb
, offset
, &asn1_ctx
, tree
, hf_p1_index
);
291 if(offset
== old_offset
){
292 proto_tree_add_text(tree
, tvb
, offset
, -1,"Internal error, zero-byte P1 PDU");
296 p1_initialize_content_globals (&asn1_ctx
, NULL
, FALSE
);
297 return tvb_length(tvb
);
301 /*--- proto_register_p1 -------------------------------------------*/
302 void proto_register_p1(void) {
305 static hf_register_info hf
[] =
307 /* "Created by defining PDU in .cnf */
308 { &hf_p1_MTABindArgument_PDU
,
309 { "MTABindArgument", "p1.MTABindArgument",
310 FT_UINT32
, BASE_DEC
, VALS(p1_MTABindArgument_vals
), 0,
311 "p1.MTABindArgument", HFILL
}},
312 { &hf_p1_MTABindResult_PDU
,
313 { "MTABindResult", "p1.MTABindResult",
314 FT_UINT32
, BASE_DEC
, VALS(p1_MTABindResult_vals
), 0,
315 "p1.MTABindResult", HFILL
}},
316 { &hf_p1_MTABindError_PDU
,
317 { "MTABindError", "p1.MTABindError",
318 FT_UINT32
, BASE_DEC
, VALS(p1_MTABindError_vals
), 0,
319 "p1.MTABindError", HFILL
}},
320 { &hf_p1_MTS_APDU_PDU
,
321 { "MTS-APDU", "p1.MTS_APDU",
322 FT_UINT32
, BASE_DEC
, VALS(p1_MTS_APDU_vals
), 0,
323 "p1.MTS_APDU", HFILL
}},
325 #include "packet-p1-hfarr.c"
328 /* List of subtrees */
329 static gint
*ett
[] = {
332 &ett_p1_content_unknown
,
333 &ett_p1_bilateral_information
,
334 &ett_p1_additional_information
,
335 &ett_p1_unknown_standard_extension
,
336 &ett_p1_unknown_extension_attribute_type
,
337 &ett_p1_unknown_tokendata_type
,
338 #include "packet-p1-ettarr.c"
341 static ei_register_info ei
[] = {
342 { &ei_p1_unknown_extension_attribute_type
, { "p1.unknown.extension_attribute_type", PI_UNDECODED
, PI_WARN
, "Unknown extension-attribute-type", EXPFILL
}},
343 { &ei_p1_unknown_standard_extension
, { "p1.unknown.standard_extension", PI_UNDECODED
, PI_WARN
, "Unknown standard-extension", EXPFILL
}},
344 { &ei_p1_unknown_built_in_content_type
, { "p1.unknown.built_in_content_type", PI_UNDECODED
, PI_WARN
, "P1 Unknown Content (unknown built-in content-type)", EXPFILL
}},
345 { &ei_p1_unknown_tokendata_type
, { "p1.unknown.tokendata_type", PI_UNDECODED
, PI_WARN
, "Unknown tokendata-type", EXPFILL
}},
348 expert_module_t
* expert_p1
;
351 /* Register protocol */
352 proto_p1
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
353 new_register_dissector("p1", dissect_p1
, proto_p1
);
355 proto_p3
= proto_register_protocol("X.411 Message Access Service", "P3", "p3");
357 /* Register fields and subtrees */
358 proto_register_field_array(proto_p1
, hf
, array_length(hf
));
359 proto_register_subtree_array(ett
, array_length(ett
));
360 expert_p1
= expert_register_protocol(proto_p1
);
361 expert_register_field_array(expert_p1
, ei
, array_length(ei
));
363 p1_extension_dissector_table
= register_dissector_table("p1.extension", "P1-EXTENSION", FT_UINT32
, BASE_DEC
);
364 p1_extension_attribute_dissector_table
= register_dissector_table("p1.extension-attribute", "P1-EXTENSION-ATTRIBUTE", FT_UINT32
, BASE_DEC
);
365 p1_tokendata_dissector_table
= register_dissector_table("p1.tokendata", "P1-TOKENDATA", FT_UINT32
, BASE_DEC
);
367 /* Register our configuration options for P1, particularly our port */
369 p1_module
= prefs_register_protocol_subtree("OSI/X.400", proto_p1
, prefs_register_p1
);
371 prefs_register_uint_preference(p1_module
, "tcp.port", "P1 TCP Port",
372 "Set the port for P1 operations (if other"
373 " than the default of 102)",
374 10, &global_p1_tcp_port
);
376 register_ber_syntax_dissector("P1 Message", proto_p1
, dissect_p1_mts_apdu
);
380 /*--- proto_reg_handoff_p1 --- */
381 void proto_reg_handoff_p1(void) {
382 dissector_handle_t p1_handle
;
384 #include "packet-p1-dis-tab.c"
386 /* APPLICATION CONTEXT */
388 oid_add_from_string("id-ac-mts-transfer","2.6.0.1.6");
390 /* ABSTRACT SYNTAXES */
392 p1_handle
= find_dissector("p1");
393 register_rtse_oid_dissector_handle("2.6.0.2.12", p1_handle
, 0, "id-as-mta-rtse", TRUE
);
394 register_rtse_oid_dissector_handle("2.6.0.2.7", p1_handle
, 0, "id-as-mtse", FALSE
);
396 register_rtse_oid_dissector_handle("applicationProtocol.1", p1_handle
, 0, "mts-transfer-protocol-1984", FALSE
);
397 register_rtse_oid_dissector_handle("applicationProtocol.12", p1_handle
, 0, "mta-transfer-protocol", FALSE
);
399 /* remember the tpkt handler for change in preferences */
400 tpkt_handle
= find_dissector("tpkt");
402 /* APPLICATION CONTEXT */
404 oid_add_from_string("id-ac-mts-access-88", id_ac_mts_access_88
);
405 oid_add_from_string("id-ac-mts-forced-access-88", id_ac_mts_forced_access_88
);
406 oid_add_from_string("id-ac-mts-access-94", id_ac_mts_access_94
);
407 oid_add_from_string("id-ac-mts-forced-access-94", id_ac_mts_forced_access_94
);
410 /* Register P3 with ROS */
411 register_ros_protocol_info(id_as_msse
, &p3_ros_info
, 0, "id-as-msse", FALSE
);
413 register_ros_protocol_info(id_as_mdse_88
, &p3_ros_info
, 0, "id-as-mdse-88", FALSE
);
414 register_ros_protocol_info(id_as_mdse_94
, &p3_ros_info
, 0, "id-as-mdse-94", FALSE
);
416 register_ros_protocol_info(id_as_mase_88
, &p3_ros_info
, 0, "id-as-mase-88", FALSE
);
417 register_ros_protocol_info(id_as_mase_94
, &p3_ros_info
, 0, "id-as-mase-94", FALSE
);
419 register_ros_protocol_info(id_as_mts
, &p3_ros_info
, 0, "id-as-mts", FALSE
);
424 prefs_register_p1(void)
426 static guint tcp_port
= 0;
428 /* de-register the old port */
429 /* port 102 is registered by TPKT - don't undo this! */
430 if((tcp_port
> 0) && (tcp_port
!= 102) && tpkt_handle
)
431 dissector_delete_uint("tcp.port", tcp_port
, tpkt_handle
);
433 /* Set our port number for future use */
434 tcp_port
= global_p1_tcp_port
;
436 if((tcp_port
> 0) && (tcp_port
!= 102) && tpkt_handle
)
437 dissector_add_uint("tcp.port", tcp_port
, tpkt_handle
);