3 * Routines for RFC2510 Certificate Management Protocol packet dissection
5 * Updated to RFC4210 CMPv2 and associated "Transport Protocols for CMP" draft
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <epan/packet.h>
39 #include <epan/oids.h>
40 #include <epan/asn1.h>
41 #include "packet-ber.h"
42 #include "packet-cmp.h"
43 #include "packet-crmf.h"
44 #include "packet-pkix1explicit.h"
45 #include "packet-pkix1implicit.h"
46 #include "packet-tcp.h"
47 #include "packet-http.h"
48 #include <epan/prefs.h>
49 #include <epan/nstime.h>
51 #define PNAME "Certificate Management Protocol"
55 #define TCP_PORT_CMP 829
57 /* desegmentation of CMP over TCP */
58 static gboolean cmp_desegment = TRUE;
60 static guint cmp_alternate_tcp_port = 0;
61 static guint cmp_alternate_http_port = 0;
62 static guint cmp_alternate_tcp_style_http_port = 0;
64 /* Initialize the protocol and registered fields */
66 static int hf_cmp_type_oid = -1;
67 static int hf_cmp_tcptrans_len = -1;
68 static int hf_cmp_tcptrans_type = -1;
69 static int hf_cmp_tcptrans_poll_ref = -1;
70 static int hf_cmp_tcptrans_next_poll_ref = -1;
71 static int hf_cmp_tcptrans_ttcb = -1;
72 static int hf_cmp_tcptrans10_version = -1;
73 static int hf_cmp_tcptrans10_flags = -1;
74 #include "packet-cmp-hf.c"
76 /* Initialize the subtree pointers */
77 static gint ett_cmp = -1;
78 #include "packet-cmp-ett.c"
80 static const char *object_identifier_id;
83 #include "packet-cmp-fn.c"
86 dissect_cmp_pdu(tvbuff_t *tvb, proto_tree *tree, asn1_ctx_t *actx)
88 return dissect_cmp_PKIMessage(FALSE, tvb, 0, actx,tree, -1);
91 #define CMP_TYPE_PKIMSG 0
92 #define CMP_TYPE_POLLREP 1
93 #define CMP_TYPE_POLLREQ 2
94 #define CMP_TYPE_NEGPOLLREP 3
95 #define CMP_TYPE_PARTIALMSGREP 4
96 #define CMP_TYPE_FINALMSGREP 5
97 #define CMP_TYPE_ERRORMSGREP 6
98 static const value_string cmp_pdu_types[] = {
99 { CMP_TYPE_PKIMSG, "pkiMsg" },
100 { CMP_TYPE_POLLREP, "pollRep" },
101 { CMP_TYPE_POLLREQ, "pollReq" },
102 { CMP_TYPE_NEGPOLLREP, "negPollRep" },
103 { CMP_TYPE_PARTIALMSGREP, "partialMsgRep" },
104 { CMP_TYPE_FINALMSGREP, "finalMsgRep" },
105 { CMP_TYPE_ERRORMSGREP, "errorMsgRep" },
110 static int dissect_cmp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
116 proto_item *item=NULL;
118 proto_tree *tree=NULL;
119 proto_tree *tcptrans_tree=NULL;
123 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
125 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMP");
127 if (check_col(pinfo->cinfo, COL_INFO)) {
128 col_clear(pinfo->cinfo, COL_INFO);
130 col_set_str(pinfo->cinfo, COL_INFO, "PKIXCMP");
134 item=proto_tree_add_item(parent_tree, proto_cmp, tvb, 0, -1, FALSE);
135 tree = proto_item_add_subtree(item, ett_cmp);
138 pdu_len=tvb_get_ntohl(tvb, 0);
139 pdu_type=tvb_get_guint8(tvb, 4);
142 /* RFC2510 TCP transport */
143 ti = proto_tree_add_item(tree, proto_cmp, tvb, offset, 5, FALSE);
144 tcptrans_tree = proto_item_add_subtree(ti, ett_cmp);
145 proto_tree_add_item(tree, hf_cmp_tcptrans_len, tvb, offset, 4, FALSE);
147 proto_tree_add_item(tree, hf_cmp_tcptrans_type, tvb, offset++, 1, FALSE);
149 /* post RFC2510 TCP transport - the former "type" field is now "version" */
150 ti = proto_tree_add_text(tree, tvb, offset, 7, "TCP transport");
151 tcptrans_tree = proto_item_add_subtree(ti, ett_cmp);
152 pdu_type=tvb_get_guint8(tvb, 6);
153 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_len, tvb, offset, 4, FALSE);
155 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans10_version, tvb, offset++, 1, FALSE);
156 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans10_flags, tvb, offset++, 1, FALSE);
157 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_type, tvb, offset++, 1, FALSE);
160 if (check_col (pinfo->cinfo, COL_INFO)) {
161 col_add_fstr (pinfo->cinfo, COL_INFO, val_to_str (pdu_type, cmp_pdu_types, "0x%x"));
165 case CMP_TYPE_PKIMSG:
166 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
167 dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
168 offset += tvb_length_remaining(tvb, offset);
170 case CMP_TYPE_POLLREP:
171 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_poll_ref, tvb, offset, 4, FALSE);
174 ts.secs = tvb_get_ntohl(tvb, 4);
176 proto_tree_add_time(tcptrans_tree, hf_cmp_tcptrans_ttcb, tvb, offset, 4, &ts);
179 case CMP_TYPE_POLLREQ:
180 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_poll_ref, tvb, offset, 4, FALSE);
183 case CMP_TYPE_NEGPOLLREP:
185 case CMP_TYPE_PARTIALMSGREP:
186 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_next_poll_ref, tvb, offset, 4, FALSE);
189 ts.secs = tvb_get_ntohl(tvb, 4);
191 proto_tree_add_time(tcptrans_tree, hf_cmp_tcptrans_ttcb, tvb, offset, 4, &ts);
194 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
195 dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
196 offset += tvb_length_remaining(tvb, offset);
198 case CMP_TYPE_FINALMSGREP:
199 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
200 dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
201 offset += tvb_length_remaining(tvb, offset);
203 case CMP_TYPE_ERRORMSGREP:
211 static void dissect_cmp_tcp_pdu_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
213 dissect_cmp_tcp_pdu(tvb, pinfo, parent_tree);
216 static guint get_cmp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
221 * Get the length of the CMP-over-TCP packet.
223 plen = tvb_get_ntohl(tvb, offset);
229 /* CMP over TCP: RFC2510 section 5.2 and "Transport Protocols for CMP" draft */
231 dissect_cmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
235 int offset=4; /* RFC2510 TCP transport header length */
237 /* only attempt to dissect it as CMP over TCP if we have
240 if (!tvb_bytes_exist(tvb, 0, 5)) {
244 pdu_len=tvb_get_ntohl(tvb, 0);
245 pdu_type=tvb_get_guint8(tvb, 4);
248 /* post RFC2510 TCP transport */
249 pdu_type = tvb_get_guint8(tvb, 7);
250 offset = 7; /* post RFC2510 TCP transport header length */
251 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
253 * It is definitely at least 3 byte for post RFC2510 TCP transport
255 if((pdu_len<=2)||(pdu_len>10000)){
259 /* RFC2510 TCP transport */
260 /* type is between 0 and 6 */
264 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
266 * It is definitely at least 1 byte to accomodate the flags byte
268 if((pdu_len<=0)||(pdu_len>10000)){
273 /* type 0 contains a PKI message and must therefore be >= 3 bytes
274 * long (flags + BER TAG + BER LENGTH
276 if((pdu_type==0)&&(pdu_len<3)){
280 tcp_dissect_pdus(tvb, pinfo, parent_tree, cmp_desegment, offset, get_cmp_pdu_len,
281 dissect_cmp_tcp_pdu_no_return);
283 return tvb_length(tvb);
288 dissect_cmp_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
290 proto_item *item=NULL;
291 proto_tree *tree=NULL;
294 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
296 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMP");
298 if (check_col(pinfo->cinfo, COL_INFO)) {
299 col_clear(pinfo->cinfo, COL_INFO);
300 col_set_str(pinfo->cinfo, COL_INFO, "PKIXCMP");
304 item=proto_tree_add_item(parent_tree, proto_cmp, tvb, 0, -1, FALSE);
305 tree = proto_item_add_subtree(item, ett_cmp);
308 return dissect_cmp_pdu(tvb, tree, &asn1_ctx);
312 /*--- proto_register_cmp ----------------------------------------------*/
313 void proto_register_cmp(void) {
316 static hf_register_info hf[] = {
318 { "InfoType", "cmp.type.oid",
319 FT_STRING, BASE_NONE, NULL, 0,
320 "Type of InfoTypeAndValue", HFILL }},
321 { &hf_cmp_tcptrans_len,
322 { "Length", "cmp.tcptrans.length",
323 FT_UINT32, BASE_DEC, NULL, 0,
324 "TCP transport Length of PDU in bytes", HFILL }},
325 { &hf_cmp_tcptrans_type,
326 { "Type", "cmp.tcptrans.type",
327 FT_UINT8, BASE_DEC, VALS(cmp_pdu_types), 0,
328 "TCP transport PDU Type", HFILL }},
329 { &hf_cmp_tcptrans_poll_ref,
330 { "Polling Reference", "cmp.tcptrans.poll_ref",
331 FT_UINT32, BASE_HEX, NULL, 0,
332 "TCP transport Polling Reference", HFILL }},
333 { &hf_cmp_tcptrans_next_poll_ref,
334 { "Next Polling Reference", "cmp.tcptrans.next_poll_ref",
335 FT_UINT32, BASE_HEX, NULL, 0,
336 "TCP transport Next Polling Reference", HFILL }},
337 { &hf_cmp_tcptrans_ttcb,
338 { "Time to check Back", "cmp.tcptrans.ttcb",
339 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0,
340 "TCP transport Time to check Back", HFILL }},
341 { &hf_cmp_tcptrans10_version,
342 { "Version", "cmp.tcptrans10.version",
343 FT_UINT8, BASE_DEC, NULL, 0,
344 "TCP transport version", HFILL }},
345 { &hf_cmp_tcptrans10_flags,
346 { "Flags", "cmp.tcptrans10.flags",
347 FT_UINT8, BASE_DEC, NULL, 0,
348 "TCP transport flags", HFILL }},
349 #include "packet-cmp-hfarr.c"
352 /* List of subtrees */
353 static gint *ett[] = {
355 #include "packet-cmp-ettarr.c"
357 module_t *cmp_module;
359 /* Register protocol */
360 proto_cmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
362 /* Register fields and subtrees */
363 proto_register_field_array(proto_cmp, hf, array_length(hf));
364 proto_register_subtree_array(ett, array_length(ett));
366 cmp_module = prefs_register_protocol(proto_cmp, proto_reg_handoff_cmp);
367 prefs_register_bool_preference(cmp_module, "desegment",
368 "Reassemble CMP-over-TCP messages spanning multiple TCP segments",
369 "Whether the CMP-over-TCP dissector should reassemble messages spanning multiple TCP segments. "
370 "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
373 prefs_register_uint_preference(cmp_module, "tcp_alternate_port",
374 "Alternate TCP port",
375 "Decode this TCP port\'s traffic as CMP. Set to \"0\" to disable.",
377 &cmp_alternate_tcp_port);
379 prefs_register_uint_preference(cmp_module, "http_alternate_port",
380 "Alternate HTTP port",
381 "Decode this TCP port\'s traffic as CMP-over-HTTP. Set to \"0\" to disable. "
382 "Use this if the Content-Type is not set correctly.",
384 &cmp_alternate_http_port);
386 prefs_register_uint_preference(cmp_module, "tcp_style_http_alternate_port",
387 "Alternate TCP-style-HTTP port",
388 "Decode this TCP port\'s traffic as TCP-transport-style CMP-over-HTTP. Set to \"0\" to disable. "
389 "Use this if the Content-Type is not set correctly.",
391 &cmp_alternate_tcp_style_http_port);
395 /*--- proto_reg_handoff_cmp -------------------------------------------*/
396 void proto_reg_handoff_cmp(void) {
397 static gboolean inited = FALSE;
398 static dissector_handle_t cmp_http_handle;
399 static dissector_handle_t cmp_tcp_style_http_handle;
400 static dissector_handle_t cmp_tcp_handle;
401 static guint cmp_alternate_tcp_port_prev = 0;
402 static guint cmp_alternate_http_port_prev = 0;
403 static guint cmp_alternate_tcp_style_http_port_prev = 0;
406 cmp_http_handle = new_create_dissector_handle(dissect_cmp_http, proto_cmp);
407 dissector_add_string("media_type", "application/pkixcmp", cmp_http_handle);
408 dissector_add_string("media_type", "application/x-pkixcmp", cmp_http_handle);
410 cmp_tcp_style_http_handle = new_create_dissector_handle(dissect_cmp_tcp_pdu, proto_cmp);
411 dissector_add_string("media_type", "application/pkixcmp-poll", cmp_tcp_style_http_handle);
412 dissector_add_string("media_type", "application/x-pkixcmp-poll", cmp_tcp_style_http_handle);
414 cmp_tcp_handle = new_create_dissector_handle(dissect_cmp_tcp, proto_cmp);
415 dissector_add("tcp.port", TCP_PORT_CMP, cmp_tcp_handle);
417 oid_add_from_string("Cryptlib-presence-check","1.3.6.1.4.1.3029.3.1.1");
418 oid_add_from_string("Cryptlib-PKIBoot","1.3.6.1.4.1.3029.3.1.2");
420 oid_add_from_string("HMAC MD5","1.3.6.1.5.5.8.1.1");
421 oid_add_from_string("HMAC SHA-1","1.3.6.1.5.5.8.1.2");
422 oid_add_from_string("HMAC TIGER","1.3.6.1.5.5.8.1.3");
423 oid_add_from_string("HMAC RIPEMD-160","1.3.6.1.5.5.8.1.4");
425 oid_add_from_string("sha256WithRSAEncryption","1.2.840.113549.1.1.11");
427 #include "packet-cmp-dis-tab.c"
431 /* change alternate TCP port if changed in the preferences */
432 if (cmp_alternate_tcp_port != cmp_alternate_tcp_port_prev) {
433 if (cmp_alternate_tcp_port_prev != 0)
434 dissector_delete("tcp.port", cmp_alternate_tcp_port_prev, cmp_tcp_handle);
435 if (cmp_alternate_tcp_port != 0)
436 dissector_add("tcp.port", cmp_alternate_tcp_port, cmp_tcp_handle);
437 cmp_alternate_tcp_port_prev = cmp_alternate_tcp_port;
440 /* change alternate HTTP port if changed in the preferences */
441 if (cmp_alternate_http_port != cmp_alternate_http_port_prev) {
442 if (cmp_alternate_http_port_prev != 0) {
443 dissector_delete("tcp.port", cmp_alternate_http_port_prev, NULL);
444 dissector_delete("http.port", cmp_alternate_http_port_prev, NULL);
446 if (cmp_alternate_http_port != 0)
447 http_dissector_add( cmp_alternate_http_port, cmp_http_handle);
448 cmp_alternate_http_port_prev = cmp_alternate_http_port;
451 /* change alternate TCP-style-HTTP port if changed in the preferences */
452 if (cmp_alternate_tcp_style_http_port != cmp_alternate_tcp_style_http_port_prev) {
453 if (cmp_alternate_tcp_style_http_port_prev != 0) {
454 dissector_delete("tcp.port", cmp_alternate_tcp_style_http_port_prev, NULL);
455 dissector_delete("http.port", cmp_alternate_tcp_style_http_port_prev, NULL);
457 if (cmp_alternate_tcp_style_http_port != 0)
458 http_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
459 cmp_alternate_tcp_style_http_port_prev = cmp_alternate_tcp_style_http_port;