3 * Routines for RFC2510 Certificate Management Protocol packet dissection
5 * Updated to RFC4210 CMPv2 and associated "Transport Protocols for CMP" draft
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
19 #include <epan/oids.h>
20 #include <epan/asn1.h>
21 #include <epan/proto_data.h>
22 #include <wsutil/array.h>
23 #include "packet-ber.h"
24 #include "packet-cmp.h"
25 #include "packet-crmf.h"
26 #include "packet-pkix1explicit.h"
27 #include "packet-pkix1implicit.h"
28 #include "packet-pkcs10.h"
29 #include "packet-tcp.h"
30 #include "packet-http.h"
31 #include <epan/prefs.h>
33 #define PNAME "Certificate Management Protocol"
37 #define TCP_PORT_CMP 829
39 void proto_register_cmp(void);
41 static dissector_handle_t cmp_http_handle
;
42 static dissector_handle_t cmp_tcp_style_http_handle
;
43 static dissector_handle_t cmp_tcp_handle
;
45 /* desegmentation of CMP over TCP */
46 static bool cmp_desegment
= true;
48 static unsigned cmp_alternate_http_port
;
49 static unsigned cmp_alternate_tcp_style_http_port
;
51 /* Initialize the protocol and registered fields */
53 static int hf_cmp_type_oid
;
54 static int hf_cmp_tcptrans_len
;
55 static int hf_cmp_tcptrans_type
;
56 static int hf_cmp_tcptrans_poll_ref
;
57 static int hf_cmp_tcptrans_next_poll_ref
;
58 static int hf_cmp_tcptrans_ttcb
;
59 static int hf_cmp_tcptrans10_version
;
60 static int hf_cmp_tcptrans10_flags
;
61 #include "packet-cmp-hf.c"
63 /* Initialize the subtree pointers */
65 #include "packet-cmp-ett.c"
66 #include "packet-cmp-fn.c"
69 dissect_cmp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
72 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
74 return dissect_cmp_PKIMessage(false, tvb
, 0, &asn1_ctx
, tree
, -1);
77 #define CMP_TYPE_PKIMSG 0
78 #define CMP_TYPE_POLLREP 1
79 #define CMP_TYPE_POLLREQ 2
80 #define CMP_TYPE_NEGPOLLREP 3
81 #define CMP_TYPE_PARTIALMSGREP 4
82 #define CMP_TYPE_FINALMSGREP 5
83 #define CMP_TYPE_ERRORMSGREP 6
84 static const value_string cmp_pdu_types
[] = {
85 { CMP_TYPE_PKIMSG
, "pkiMsg" },
86 { CMP_TYPE_POLLREP
, "pollRep" },
87 { CMP_TYPE_POLLREQ
, "pollReq" },
88 { CMP_TYPE_NEGPOLLREP
, "negPollRep" },
89 { CMP_TYPE_PARTIALMSGREP
, "partialMsgRep" },
90 { CMP_TYPE_FINALMSGREP
, "finalMsgRep" },
91 { CMP_TYPE_ERRORMSGREP
, "errorMsgRep" },
96 static int dissect_cmp_tcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
101 proto_item
*item
=NULL
;
103 proto_tree
*tree
=NULL
;
104 proto_tree
*tcptrans_tree
=NULL
;
107 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CMP");
108 col_set_str(pinfo
->cinfo
, COL_INFO
, "PKIXCMP");
111 item
=proto_tree_add_item(parent_tree
, proto_cmp
, tvb
, 0, -1, ENC_NA
);
112 tree
= proto_item_add_subtree(item
, ett_cmp
);
115 pdu_len
=tvb_get_ntohl(tvb
, 0);
116 pdu_type
=tvb_get_uint8(tvb
, 4);
119 /* RFC2510 TCP transport */
120 ti
= proto_tree_add_item(tree
, proto_cmp
, tvb
, offset
, 5, ENC_NA
);
121 tcptrans_tree
= proto_item_add_subtree(ti
, ett_cmp
);
122 proto_tree_add_item(tree
, hf_cmp_tcptrans_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
124 proto_tree_add_item(tree
, hf_cmp_tcptrans_type
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
126 /* post RFC2510 TCP transport - the former "type" field is now "version" */
127 tcptrans_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, 7, ett_cmp
, NULL
, "TCP transport");
128 pdu_type
=tvb_get_uint8(tvb
, 6);
129 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_len
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
131 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans10_version
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
132 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans10_flags
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
133 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_type
, tvb
, offset
++, 1, ENC_BIG_ENDIAN
);
136 col_add_str (pinfo
->cinfo
, COL_INFO
, val_to_str (pdu_type
, cmp_pdu_types
, "0x%x"));
139 case CMP_TYPE_PKIMSG
:
140 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), pdu_len
);
141 dissect_cmp_pdu(next_tvb
, pinfo
, tree
, NULL
);
142 offset
+= tvb_reported_length_remaining(tvb
, offset
);
144 case CMP_TYPE_POLLREP
:
145 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_poll_ref
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
148 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_ttcb
, tvb
, offset
, 4, ENC_TIME_SECS
|ENC_BIG_ENDIAN
);
151 case CMP_TYPE_POLLREQ
:
152 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_poll_ref
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
155 case CMP_TYPE_NEGPOLLREP
:
157 case CMP_TYPE_PARTIALMSGREP
:
158 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_next_poll_ref
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
161 proto_tree_add_item(tcptrans_tree
, hf_cmp_tcptrans_ttcb
, tvb
, offset
, 4, ENC_TIME_SECS
|ENC_BIG_ENDIAN
);
164 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), pdu_len
);
165 dissect_cmp_pdu(next_tvb
, pinfo
, tree
, NULL
);
166 offset
+= tvb_reported_length_remaining(tvb
, offset
);
168 case CMP_TYPE_FINALMSGREP
:
169 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), pdu_len
);
170 dissect_cmp_pdu(next_tvb
, pinfo
, tree
, NULL
);
171 offset
+= tvb_reported_length_remaining(tvb
, offset
);
173 case CMP_TYPE_ERRORMSGREP
:
181 static unsigned get_cmp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
182 int offset
, void *data _U_
)
187 * Get the length of the CMP-over-TCP packet.
189 plen
= tvb_get_ntohl(tvb
, offset
);
195 /* CMP over TCP: RFC2510 section 5.2 and "Transport Protocols for CMP" draft */
197 dissect_cmp_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data
)
201 int offset
=4; /* RFC2510 TCP transport header length */
203 /* only attempt to dissect it as CMP over TCP if we have
206 if (!tvb_bytes_exist(tvb
, 0, 5)) {
210 pdu_len
=tvb_get_ntohl(tvb
, 0);
211 pdu_type
=tvb_get_uint8(tvb
, 4);
214 /* post RFC2510 TCP transport */
215 pdu_type
= tvb_get_uint8(tvb
, 7);
216 offset
= 7; /* post RFC2510 TCP transport header length */
217 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
219 * It is definitely at least 3 byte for post RFC2510 TCP transport
221 if((pdu_len
<=2)||(pdu_len
>10000)){
225 /* RFC2510 TCP transport */
226 /* type is between 0 and 6 */
230 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
232 * It is definitely at least 1 byte to accommodate the flags byte
234 if((pdu_len
<=0)||(pdu_len
>10000)){
239 /* type 0 contains a PKI message and must therefore be >= 3 bytes
240 * long (flags + BER TAG + BER LENGTH
242 if((pdu_type
==0)&&(pdu_len
<3)){
246 tcp_dissect_pdus(tvb
, pinfo
, parent_tree
, cmp_desegment
, offset
, get_cmp_pdu_len
,
247 dissect_cmp_tcp_pdu
, data
);
249 return tvb_captured_length(tvb
);
254 dissect_cmp_http(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
256 proto_item
*item
=NULL
;
257 proto_tree
*tree
=NULL
;
259 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CMP");
260 col_set_str(pinfo
->cinfo
, COL_INFO
, "PKIXCMP");
263 item
=proto_tree_add_item(parent_tree
, proto_cmp
, tvb
, 0, -1, ENC_NA
);
264 tree
= proto_item_add_subtree(item
, ett_cmp
);
267 return dissect_cmp_pdu(tvb
, pinfo
, tree
, NULL
);
271 /*--- proto_register_cmp ----------------------------------------------*/
272 void proto_register_cmp(void) {
275 static hf_register_info hf
[] = {
277 { "InfoType", "cmp.type.oid",
278 FT_STRING
, BASE_NONE
, NULL
, 0,
279 "Type of InfoTypeAndValue", HFILL
}},
280 { &hf_cmp_tcptrans_len
,
281 { "Length", "cmp.tcptrans.length",
282 FT_UINT32
, BASE_DEC
, NULL
, 0,
283 "TCP transport Length of PDU in bytes", HFILL
}},
284 { &hf_cmp_tcptrans_type
,
285 { "Type", "cmp.tcptrans.type",
286 FT_UINT8
, BASE_DEC
, VALS(cmp_pdu_types
), 0,
287 "TCP transport PDU Type", HFILL
}},
288 { &hf_cmp_tcptrans_poll_ref
,
289 { "Polling Reference", "cmp.tcptrans.poll_ref",
290 FT_UINT32
, BASE_HEX
, NULL
, 0,
291 "TCP transport Polling Reference", HFILL
}},
292 { &hf_cmp_tcptrans_next_poll_ref
,
293 { "Next Polling Reference", "cmp.tcptrans.next_poll_ref",
294 FT_UINT32
, BASE_HEX
, NULL
, 0,
295 "TCP transport Next Polling Reference", HFILL
}},
296 { &hf_cmp_tcptrans_ttcb
,
297 { "Time to check Back", "cmp.tcptrans.ttcb",
298 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0,
299 "TCP transport Time to check Back", HFILL
}},
300 { &hf_cmp_tcptrans10_version
,
301 { "Version", "cmp.tcptrans10.version",
302 FT_UINT8
, BASE_DEC
, NULL
, 0,
303 "TCP transport version", HFILL
}},
304 { &hf_cmp_tcptrans10_flags
,
305 { "Flags", "cmp.tcptrans10.flags",
306 FT_UINT8
, BASE_DEC
, NULL
, 0,
307 "TCP transport flags", HFILL
}},
308 #include "packet-cmp-hfarr.c"
311 /* List of subtrees */
312 static int *ett
[] = {
314 #include "packet-cmp-ettarr.c"
316 module_t
*cmp_module
;
318 /* Register protocol */
319 proto_cmp
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
321 /* Register fields and subtrees */
322 proto_register_field_array(proto_cmp
, hf
, array_length(hf
));
323 proto_register_subtree_array(ett
, array_length(ett
));
325 /* Register preferences */
326 cmp_module
= prefs_register_protocol(proto_cmp
, proto_reg_handoff_cmp
);
327 prefs_register_bool_preference(cmp_module
, "desegment",
328 "Reassemble CMP-over-TCP messages spanning multiple TCP segments",
329 "Whether the CMP-over-TCP dissector should reassemble messages spanning multiple TCP segments. "
330 "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
333 prefs_register_uint_preference(cmp_module
, "http_alternate_port",
334 "Alternate HTTP port",
335 "Decode this TCP port\'s traffic as CMP-over-HTTP. Set to \"0\" to disable. "
336 "Use this if the Content-Type is not set correctly.",
338 &cmp_alternate_http_port
);
340 prefs_register_uint_preference(cmp_module
, "tcp_style_http_alternate_port",
341 "Alternate TCP-style-HTTP port",
342 "Decode this TCP port\'s traffic as TCP-transport-style CMP-over-HTTP. Set to \"0\" to disable. "
343 "Use this if the Content-Type is not set correctly.",
345 &cmp_alternate_tcp_style_http_port
);
347 /* Register dissectors */
348 cmp_http_handle
= register_dissector("cmp.http", dissect_cmp_http
, proto_cmp
);
349 cmp_tcp_style_http_handle
= register_dissector("cmp.tcp_pdu", dissect_cmp_tcp_pdu
, proto_cmp
);
350 cmp_tcp_handle
= register_dissector("cmp", dissect_cmp_tcp
, proto_cmp
);
351 register_ber_syntax_dissector("PKIMessage", proto_cmp
, dissect_cmp_pdu
);
355 /*--- proto_reg_handoff_cmp -------------------------------------------*/
356 void proto_reg_handoff_cmp(void) {
357 static bool inited
= false;
358 static unsigned cmp_alternate_http_port_prev
= 0;
359 static unsigned cmp_alternate_tcp_style_http_port_prev
= 0;
362 dissector_add_string("media_type", "application/pkixcmp", cmp_http_handle
);
363 dissector_add_string("media_type", "application/x-pkixcmp", cmp_http_handle
);
365 dissector_add_string("media_type", "application/pkixcmp-poll", cmp_tcp_style_http_handle
);
366 dissector_add_string("media_type", "application/x-pkixcmp-poll", cmp_tcp_style_http_handle
);
368 dissector_add_uint_with_preference("tcp.port", TCP_PORT_CMP
, cmp_tcp_handle
);
370 oid_add_from_string("Cryptlib-presence-check","1.3.6.1.4.1.3029.3.1.1");
371 oid_add_from_string("Cryptlib-PKIBoot","1.3.6.1.4.1.3029.3.1.2");
373 oid_add_from_string("HMAC MD5","1.3.6.1.5.5.8.1.1");
374 oid_add_from_string("HMAC SHA-1","1.3.6.1.5.5.8.1.2");
375 oid_add_from_string("HMAC TIGER","1.3.6.1.5.5.8.1.3");
376 oid_add_from_string("HMAC RIPEMD-160","1.3.6.1.5.5.8.1.4");
378 #include "packet-cmp-dis-tab.c"
382 /* change alternate HTTP port if changed in the preferences */
383 if (cmp_alternate_http_port
!= cmp_alternate_http_port_prev
) {
384 if (cmp_alternate_http_port_prev
!= 0) {
385 http_tcp_dissector_delete(cmp_alternate_http_port_prev
);
387 if (cmp_alternate_http_port
!= 0)
388 http_tcp_dissector_add( cmp_alternate_http_port
, cmp_http_handle
);
389 cmp_alternate_http_port_prev
= cmp_alternate_http_port
;
392 /* change alternate TCP-style-HTTP port if changed in the preferences */
393 if (cmp_alternate_tcp_style_http_port
!= cmp_alternate_tcp_style_http_port_prev
) {
394 if (cmp_alternate_tcp_style_http_port_prev
!= 0) {
395 http_tcp_dissector_delete(cmp_alternate_tcp_style_http_port_prev
);
397 if (cmp_alternate_tcp_style_http_port
!= 0)
398 http_tcp_dissector_add( cmp_alternate_tcp_style_http_port
, cmp_tcp_style_http_handle
);
399 cmp_alternate_tcp_style_http_port_prev
= cmp_alternate_tcp_style_http_port
;