e7f3c7589418fa9b2b8e64baf0501be41ac97be4
[obnox/wireshark/wip.git] / asn1 / cmp / packet-cmp-template.c
1 /* packet-cmp.c
2  *
3  * Routines for RFC2510 Certificate Management Protocol packet dissection
4  *   Ronnie Sahlberg 2004
5  * Updated to RFC4210 CMPv2 and associated "Transport Protocols for CMP" draft
6  *   Martin Peylo 2008
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
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.
18  *
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.
23  *
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.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <glib.h>
34 #include <epan/packet.h>
35
36 #include <epan/oids.h>
37 #include <epan/asn1.h>
38 #include "packet-ber.h"
39 #include "packet-cmp.h"
40 #include "packet-crmf.h"
41 #include "packet-pkix1explicit.h"
42 #include "packet-pkix1implicit.h"
43 #include "packet-tcp.h"
44 #include "packet-http.h"
45 #include <epan/prefs.h>
46 #include <epan/nstime.h>
47
48 #define PNAME  "Certificate Management Protocol"
49 #define PSNAME "CMP"
50 #define PFNAME "cmp"
51
52 #define TCP_PORT_CMP 829
53
54 /* desegmentation of CMP over TCP */
55 static gboolean cmp_desegment = TRUE;
56
57 static guint cmp_alternate_tcp_port = 0;
58 static guint cmp_alternate_http_port = 0;
59 static guint cmp_alternate_tcp_style_http_port = 0;
60
61 /* Initialize the protocol and registered fields */
62 static int proto_cmp = -1;
63 static int hf_cmp_type_oid = -1;
64 static int hf_cmp_tcptrans_len = -1;
65 static int hf_cmp_tcptrans_type = -1;
66 static int hf_cmp_tcptrans_poll_ref = -1;
67 static int hf_cmp_tcptrans_next_poll_ref = -1;
68 static int hf_cmp_tcptrans_ttcb = -1;
69 static int hf_cmp_tcptrans10_version = -1;
70 static int hf_cmp_tcptrans10_flags = -1;
71 #include "packet-cmp-hf.c"
72
73 /* Initialize the subtree pointers */
74 static gint ett_cmp = -1;
75 #include "packet-cmp-ett.c"
76
77 static const char *object_identifier_id;
78
79
80 #include "packet-cmp-fn.c"
81
82 static int
83 dissect_cmp_pdu(tvbuff_t *tvb, proto_tree *tree, asn1_ctx_t *actx)
84 {
85         return dissect_cmp_PKIMessage(FALSE, tvb, 0, actx,tree, -1);
86 }
87
88 #define CMP_TYPE_PKIMSG         0
89 #define CMP_TYPE_POLLREP        1
90 #define CMP_TYPE_POLLREQ        2
91 #define CMP_TYPE_NEGPOLLREP     3
92 #define CMP_TYPE_PARTIALMSGREP  4
93 #define CMP_TYPE_FINALMSGREP    5
94 #define CMP_TYPE_ERRORMSGREP    6
95 static const value_string cmp_pdu_types[] = {
96         { CMP_TYPE_PKIMSG,              "pkiMsg" },
97         { CMP_TYPE_POLLREP,             "pollRep" },
98         { CMP_TYPE_POLLREQ,             "pollReq" },
99         { CMP_TYPE_NEGPOLLREP,          "negPollRep" },
100         { CMP_TYPE_PARTIALMSGREP,       "partialMsgRep" },
101         { CMP_TYPE_FINALMSGREP,         "finalMsgRep" },
102         { CMP_TYPE_ERRORMSGREP,         "errorMsgRep" },
103         { 0, NULL },
104 };
105
106
107 static int dissect_cmp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
108 {
109         tvbuff_t   *next_tvb;
110         guint32    pdu_len;
111         guint8     pdu_type;
112         nstime_t   ts;
113         proto_item *item=NULL;
114         proto_item *ti=NULL;
115         proto_tree *tree=NULL;
116         proto_tree *tcptrans_tree=NULL;
117         asn1_ctx_t asn1_ctx;
118         int offset=0;
119
120         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
121
122         col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMP");
123
124         col_set_str(pinfo->cinfo, COL_INFO, "PKIXCMP");
125
126         if(parent_tree){
127                 item=proto_tree_add_item(parent_tree, proto_cmp, tvb, 0, -1, FALSE);
128                 tree = proto_item_add_subtree(item, ett_cmp);
129         }
130
131         pdu_len=tvb_get_ntohl(tvb, 0);
132         pdu_type=tvb_get_guint8(tvb, 4);
133
134         if (pdu_type < 10) {
135                 /* RFC2510 TCP transport */
136                 ti = proto_tree_add_item(tree, proto_cmp, tvb, offset, 5, FALSE);
137                 tcptrans_tree = proto_item_add_subtree(ti, ett_cmp);
138                 proto_tree_add_item(tree, hf_cmp_tcptrans_len, tvb, offset, 4, FALSE);
139                 offset += 4;
140                 proto_tree_add_item(tree, hf_cmp_tcptrans_type, tvb, offset++, 1, FALSE);
141         } else {
142                 /* post RFC2510 TCP transport - the former "type" field is now "version" */
143                 ti = proto_tree_add_text(tree, tvb, offset, 7, "TCP transport");
144                 tcptrans_tree = proto_item_add_subtree(ti, ett_cmp);
145                 pdu_type=tvb_get_guint8(tvb, 6);
146                 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_len, tvb, offset, 4, FALSE);
147                 offset += 4;
148                 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans10_version, tvb, offset++, 1, FALSE);
149                 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans10_flags, tvb, offset++, 1, FALSE);
150                 proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_type, tvb, offset++, 1, FALSE);
151         }
152
153         col_add_str (pinfo->cinfo, COL_INFO, val_to_str (pdu_type, cmp_pdu_types, "0x%x"));
154
155         switch(pdu_type){
156                 case CMP_TYPE_PKIMSG:
157                         next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
158                         dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
159                         offset += tvb_length_remaining(tvb, offset);
160                         break;
161                 case CMP_TYPE_POLLREP:
162                         proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_poll_ref, tvb, offset, 4, FALSE);
163                         offset += 4;
164
165                         ts.secs = tvb_get_ntohl(tvb, 4);
166                         ts.nsecs = 0;
167                         proto_tree_add_time(tcptrans_tree, hf_cmp_tcptrans_ttcb, tvb, offset, 4, &ts);
168                         offset += 4;
169                         break;
170                 case CMP_TYPE_POLLREQ:
171                         proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_poll_ref, tvb, offset, 4, FALSE);
172                         offset += 4;
173                         break;
174                 case CMP_TYPE_NEGPOLLREP:
175                         break;
176                 case CMP_TYPE_PARTIALMSGREP:
177                         proto_tree_add_item(tcptrans_tree, hf_cmp_tcptrans_next_poll_ref, tvb, offset, 4, FALSE);
178                         offset += 4;
179
180                         ts.secs = tvb_get_ntohl(tvb, 4);
181                         ts.nsecs = 0;
182                         proto_tree_add_time(tcptrans_tree, hf_cmp_tcptrans_ttcb, tvb, offset, 4, &ts);
183                         offset += 4;
184
185                         next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
186                         dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
187                         offset += tvb_length_remaining(tvb, offset);
188                         break;
189                 case CMP_TYPE_FINALMSGREP:
190                         next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), pdu_len);
191                         dissect_cmp_pdu(next_tvb, tree, &asn1_ctx);
192                         offset += tvb_length_remaining(tvb, offset);
193                         break;
194                 case CMP_TYPE_ERRORMSGREP:
195                         /*XXX to be added*/
196                         break;
197         }
198
199         return offset;
200 }
201
202 static void dissect_cmp_tcp_pdu_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
203 {
204         dissect_cmp_tcp_pdu(tvb, pinfo, parent_tree);
205 }
206
207 static guint get_cmp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
208 {
209         guint32 plen;
210
211         /*
212          * Get the length of the CMP-over-TCP packet.
213          */
214         plen = tvb_get_ntohl(tvb, offset);
215
216         return plen+4;
217 }
218
219
220 /* CMP over TCP: RFC2510 section 5.2 and "Transport Protocols for CMP" draft */
221         static int
222 dissect_cmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
223 {
224         guint32 pdu_len;
225         guint8 pdu_type;
226         int offset=4; /* RFC2510 TCP transport header length */
227
228         /* only attempt to dissect it as CMP over TCP if we have
229          * at least 5 bytes.
230          */
231         if (!tvb_bytes_exist(tvb, 0, 5)) {
232                 return 0;
233         }
234
235         pdu_len=tvb_get_ntohl(tvb, 0);
236         pdu_type=tvb_get_guint8(tvb, 4);
237
238         if(pdu_type == 10) {
239                 /* post RFC2510 TCP transport */
240                 pdu_type = tvb_get_guint8(tvb, 7);
241                 offset = 7; /* post RFC2510 TCP transport header length */
242                 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
243                  * in size.
244                  * It is definitely at least 3 byte for post RFC2510 TCP transport
245                  */
246                 if((pdu_len<=2)||(pdu_len>10000)){
247                         return 0;
248                 }
249         } else {
250                 /* RFC2510 TCP transport */
251                 /* type is between 0 and 6 */
252                 if(pdu_type>6){
253                         return 0;
254                 }
255                 /* arbitrary limit: assume a CMP over TCP pdu is never >10000 bytes
256                  * in size.
257                  * It is definitely at least 1 byte to accomodate the flags byte
258                  */
259                 if((pdu_len<=0)||(pdu_len>10000)){
260                         return 0;
261                 }
262         }
263
264         /* type 0 contains a PKI message and must therefore be >= 3 bytes
265          * long (flags + BER TAG + BER LENGTH
266          */
267         if((pdu_type==0)&&(pdu_len<3)){
268                 return 0;
269         }
270
271         tcp_dissect_pdus(tvb, pinfo, parent_tree, cmp_desegment, offset, get_cmp_pdu_len,
272                         dissect_cmp_tcp_pdu_no_return);
273
274         return tvb_length(tvb);
275 }
276
277
278         static int
279 dissect_cmp_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
280 {
281         proto_item *item=NULL;
282         proto_tree *tree=NULL;
283         asn1_ctx_t asn1_ctx;
284
285         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
286
287         col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMP");
288
289         col_set_str(pinfo->cinfo, COL_INFO, "PKIXCMP");
290
291         if(parent_tree){
292                 item=proto_tree_add_item(parent_tree, proto_cmp, tvb, 0, -1, FALSE);
293                 tree = proto_item_add_subtree(item, ett_cmp);
294         }
295
296         return dissect_cmp_pdu(tvb, tree, &asn1_ctx);
297 }
298
299
300 /*--- proto_register_cmp ----------------------------------------------*/
301 void proto_register_cmp(void) {
302
303         /* List of fields */
304         static hf_register_info hf[] = {
305                 { &hf_cmp_type_oid,
306                         { "InfoType", "cmp.type.oid",
307                                 FT_STRING, BASE_NONE, NULL, 0,
308                                 "Type of InfoTypeAndValue", HFILL }},
309                 { &hf_cmp_tcptrans_len,
310                         { "Length", "cmp.tcptrans.length",
311                                 FT_UINT32, BASE_DEC, NULL, 0,
312                                 "TCP transport Length of PDU in bytes", HFILL }},
313                 { &hf_cmp_tcptrans_type,
314                         { "Type", "cmp.tcptrans.type",
315                                 FT_UINT8, BASE_DEC, VALS(cmp_pdu_types), 0,
316                                 "TCP transport PDU Type", HFILL }},
317                 { &hf_cmp_tcptrans_poll_ref,
318                         { "Polling Reference", "cmp.tcptrans.poll_ref",
319                                 FT_UINT32, BASE_HEX, NULL, 0,
320                                 "TCP transport Polling Reference", HFILL }},
321                 { &hf_cmp_tcptrans_next_poll_ref,
322                         { "Next Polling Reference", "cmp.tcptrans.next_poll_ref",
323                                 FT_UINT32, BASE_HEX, NULL, 0,
324                                 "TCP transport Next Polling Reference", HFILL }},
325                 { &hf_cmp_tcptrans_ttcb,
326                         { "Time to check Back", "cmp.tcptrans.ttcb",
327                                 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0,
328                                 "TCP transport Time to check Back", HFILL }},
329                 { &hf_cmp_tcptrans10_version,
330                         { "Version", "cmp.tcptrans10.version",
331                                 FT_UINT8, BASE_DEC, NULL, 0,
332                                 "TCP transport version", HFILL }},
333                 { &hf_cmp_tcptrans10_flags,
334                         { "Flags", "cmp.tcptrans10.flags",
335                                 FT_UINT8, BASE_DEC, NULL, 0,
336                                 "TCP transport flags", HFILL }},
337 #include "packet-cmp-hfarr.c"
338         };
339
340         /* List of subtrees */
341         static gint *ett[] = {
342                 &ett_cmp,
343 #include "packet-cmp-ettarr.c"
344         };
345         module_t *cmp_module;
346
347         /* Register protocol */
348         proto_cmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
349
350         /* Register fields and subtrees */
351         proto_register_field_array(proto_cmp, hf, array_length(hf));
352         proto_register_subtree_array(ett, array_length(ett));
353
354         cmp_module = prefs_register_protocol(proto_cmp, proto_reg_handoff_cmp);
355         prefs_register_bool_preference(cmp_module, "desegment",
356                         "Reassemble CMP-over-TCP messages spanning multiple TCP segments",
357                         "Whether the CMP-over-TCP dissector should reassemble messages spanning multiple TCP segments. "
358                         "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
359                         &cmp_desegment);
360
361         prefs_register_uint_preference(cmp_module, "tcp_alternate_port",
362                         "Alternate TCP port",
363                         "Decode this TCP port\'s traffic as CMP. Set to \"0\" to disable.",
364                         10,
365                         &cmp_alternate_tcp_port);
366
367         prefs_register_uint_preference(cmp_module, "http_alternate_port",
368                         "Alternate HTTP port",
369                         "Decode this TCP port\'s traffic as CMP-over-HTTP. Set to \"0\" to disable. "
370                         "Use this if the Content-Type is not set correctly.",
371                         10,
372                         &cmp_alternate_http_port);
373
374         prefs_register_uint_preference(cmp_module, "tcp_style_http_alternate_port",
375                         "Alternate TCP-style-HTTP port",
376                         "Decode this TCP port\'s traffic as TCP-transport-style CMP-over-HTTP. Set to \"0\" to disable. "
377                         "Use this if the Content-Type is not set correctly.",
378                         10,
379                         &cmp_alternate_tcp_style_http_port);
380 }
381
382
383 /*--- proto_reg_handoff_cmp -------------------------------------------*/
384 void proto_reg_handoff_cmp(void) {
385         static gboolean inited = FALSE;
386         static dissector_handle_t cmp_http_handle;
387         static dissector_handle_t cmp_tcp_style_http_handle;
388         static dissector_handle_t cmp_tcp_handle;
389         static guint cmp_alternate_tcp_port_prev = 0;
390         static guint cmp_alternate_http_port_prev = 0;
391         static guint cmp_alternate_tcp_style_http_port_prev = 0;
392
393         if (!inited) {
394                 cmp_http_handle = new_create_dissector_handle(dissect_cmp_http, proto_cmp);
395                 dissector_add_string("media_type", "application/pkixcmp", cmp_http_handle);
396                 dissector_add_string("media_type", "application/x-pkixcmp", cmp_http_handle);
397
398                 cmp_tcp_style_http_handle = new_create_dissector_handle(dissect_cmp_tcp_pdu, proto_cmp);
399                 dissector_add_string("media_type", "application/pkixcmp-poll", cmp_tcp_style_http_handle);
400                 dissector_add_string("media_type", "application/x-pkixcmp-poll", cmp_tcp_style_http_handle);
401
402                 cmp_tcp_handle = new_create_dissector_handle(dissect_cmp_tcp, proto_cmp);
403                 dissector_add_uint("tcp.port", TCP_PORT_CMP, cmp_tcp_handle);
404
405                 oid_add_from_string("Cryptlib-presence-check","1.3.6.1.4.1.3029.3.1.1");
406                 oid_add_from_string("Cryptlib-PKIBoot","1.3.6.1.4.1.3029.3.1.2");
407
408                 oid_add_from_string("HMAC MD5","1.3.6.1.5.5.8.1.1");
409                 oid_add_from_string("HMAC SHA-1","1.3.6.1.5.5.8.1.2");
410                 oid_add_from_string("HMAC TIGER","1.3.6.1.5.5.8.1.3");
411                 oid_add_from_string("HMAC RIPEMD-160","1.3.6.1.5.5.8.1.4");
412
413                 oid_add_from_string("sha256WithRSAEncryption","1.2.840.113549.1.1.11");
414
415 #include "packet-cmp-dis-tab.c"
416                 inited = TRUE;
417         }
418
419         /* change alternate TCP port if changed in the preferences */
420         if (cmp_alternate_tcp_port != cmp_alternate_tcp_port_prev) {
421                 if (cmp_alternate_tcp_port_prev != 0)
422                         dissector_delete_uint("tcp.port", cmp_alternate_tcp_port_prev, cmp_tcp_handle);
423                 if (cmp_alternate_tcp_port != 0)
424                         dissector_add_uint("tcp.port", cmp_alternate_tcp_port, cmp_tcp_handle);
425                 cmp_alternate_tcp_port_prev = cmp_alternate_tcp_port;
426         }
427
428         /* change alternate HTTP port if changed in the preferences */
429         if (cmp_alternate_http_port != cmp_alternate_http_port_prev) {
430                 if (cmp_alternate_http_port_prev != 0) {
431                         dissector_delete_uint("tcp.port", cmp_alternate_http_port_prev, NULL);
432                         dissector_delete_uint("http.port", cmp_alternate_http_port_prev, NULL);
433                 }
434                 if (cmp_alternate_http_port != 0)
435                         http_dissector_add( cmp_alternate_http_port, cmp_http_handle);
436                 cmp_alternate_http_port_prev = cmp_alternate_http_port;
437         }
438
439         /* change alternate TCP-style-HTTP port if changed in the preferences */
440         if (cmp_alternate_tcp_style_http_port != cmp_alternate_tcp_style_http_port_prev) {
441                 if (cmp_alternate_tcp_style_http_port_prev != 0) {
442                         dissector_delete_uint("tcp.port", cmp_alternate_tcp_style_http_port_prev, NULL);
443                         dissector_delete_uint("http.port", cmp_alternate_tcp_style_http_port_prev, NULL);
444                 }
445                 if (cmp_alternate_tcp_style_http_port != 0)
446                         http_dissector_add( cmp_alternate_tcp_style_http_port, cmp_tcp_style_http_handle);
447                 cmp_alternate_tcp_style_http_port_prev = cmp_alternate_tcp_style_http_port;
448         }
449
450 }
451