Apparently bit 0x80 of a SAMR domain handle is the permission to look
[metze/wireshark/wip.git] / packet-isakmp.c
1 /* packet-isakmp.c
2  * Routines for the Internet Security Association and Key Management Protocol
3  * (ISAKMP) (RFC 2408) and the Internet IP Security Domain of Interpretation
4  * for ISAKMP (RFC 2407)
5  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
6  *
7  * $Id: packet-isakmp.c,v 1.60 2003/01/20 22:27:03 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <glib.h>
36
37 #ifdef NEED_SNPRINTF_H
38 # include "snprintf.h"
39 #endif
40
41 #include <epan/packet.h>
42 #include "ipproto.h"
43
44 #define isakmp_min(a, b)  ((a<b) ? a : b)
45
46 static int proto_isakmp = -1;
47
48 static gint ett_isakmp = -1;
49 static gint ett_isakmp_flags = -1;
50 static gint ett_isakmp_payload = -1;
51
52 #define UDP_PORT_ISAKMP 500
53 #define TCP_PORT_ISAKMP 500
54
55 #define NUM_PROTO_TYPES 5
56 #define proto2str(t)    \
57   ((t < NUM_PROTO_TYPES) ? prototypestr[t] : "UNKNOWN-PROTO-TYPE")
58
59 static const char *prototypestr[NUM_PROTO_TYPES] = {
60   "RESERVED",
61   "ISAKMP",
62   "IPSEC_AH",
63   "IPSEC_ESP",
64   "IPCOMP"
65 };
66
67 #define NUM_P1_ATT_TYPES        17
68 #define p1_atttype2str(t)       \
69   ((t < NUM_P1_ATT_TYPES) ? p1_atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
70
71 static const char *p1_atttypestr[NUM_P1_ATT_TYPES] = {
72   "UNKNOWN-ATTRIBUTE-TYPE",
73   "Encryption-Algorithm",
74   "Hash-Algorithm",
75   "Authentication-Method",
76   "Group-Description",
77   "Group-Type",
78   "Group-Prime",
79   "Group-Generator-One",
80   "Group-Generator-Two",
81   "Group-Curve-A",
82   "Group-Curve-B",
83   "Life-Type",
84   "Life-Duration",
85   "PRF",
86   "Key-Length",
87   "Field-Size",
88   "Group-Order"
89 };
90
91 #define NUM_ATT_TYPES   11
92 #define atttype2str(t)  \
93   ((t < NUM_ATT_TYPES) ? atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
94
95 static const char *atttypestr[NUM_ATT_TYPES] = {
96   "UNKNOWN-ATTRIBUTE-TYPE",
97   "SA-Life-Type",
98   "SA-Life-Duration",
99   "Group-Description",
100   "Encapsulation-Mode",
101   "Authentication-Algorithm",
102   "Key-Length",
103   "Key-Rounds",
104   "Compress-Dictinary-Size",
105   "Compress-Private-Algorithm",
106   "ECN Tunnel"
107 };
108
109 #define NUM_TRANS_TYPES 2
110 #define trans2str(t)    \
111   ((t < NUM_TRANS_TYPES) ? transtypestr[t] : "UNKNOWN-TRANS-TYPE")
112
113 static const char *transtypestr[NUM_TRANS_TYPES] = {
114   "RESERVED",
115   "KEY_IKE"
116 };
117
118 #define NUM_AH_TRANS_TYPES      8
119 #define ah_trans2str(t)         \
120   ((t < NUM_AH_TRANS_TYPES) ? ah_transtypestr[t] : "UNKNOWN-AH-TRANS-TYPE")
121
122 static const char *ah_transtypestr[NUM_AH_TRANS_TYPES] = {
123   "RESERVED",
124   "RESERVED",
125   "MD5",
126   "SHA",
127   "DES",
128   "SHA2-256",
129   "SHA2-384",
130   "SHA2-512"
131 };
132
133 #define NUM_ESP_TRANS_TYPES     13
134 #define esp_trans2str(t)        \
135   ((t < NUM_ESP_TRANS_TYPES) ? esp_transtypestr[t] : "UNKNOWN-ESP-TRANS-TYPE")
136
137 static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
138   "RESERVED",
139   "DES-IV64",
140   "DES",
141   "3DES",
142   "RC5",
143   "IDEA",
144   "CAST",
145   "BLOWFISH",
146   "3IDEA",
147   "DES-IV32",
148   "RC4",
149   "NULL",
150   "AES"
151 };
152
153 #define NUM_IPCOMP_TRANS_TYPES    5
154 #define ipcomp_trans2str(t)  \
155   ((t < NUM_IPCOMP_TRANS_TYPES) ? ipcomp_transtypestr[t] : "UNKNOWN-IPCOMP-TRANS-TYPE")
156
157 static const char *ipcomp_transtypestr[NUM_IPCOMP_TRANS_TYPES] = {
158   "RESERVED",
159   "OUI",
160   "DEFLATE",
161   "LZS",
162   "LZJH"
163 };
164
165 #define NUM_ID_TYPES    12
166 #define id2str(t)       \
167   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
168
169 static const char *idtypestr[NUM_ID_TYPES] = {
170   "RESERVED",
171   "IPV4_ADDR",
172   "FQDN",
173   "USER_FQDN",
174   "IPV4_ADDR_SUBNET",
175   "IPV6_ADDR",
176   "IPV6_ADDR_SUBNET",
177   "IPV4_ADDR_RANGE",
178   "IPV6_ADDR_RANGE",
179   "DER_ASN1_DN",
180   "DER_ASN1_GN",
181   "KEY_ID"
182 };
183
184 #define NUM_GRPDESC_TYPES 14
185 #define grpdesc2str(t) ((t < NUM_GRPDESC_TYPES) ? grpdescstr[t] : "UKNOWEN GROUP DESCRIPTION")
186
187 static const char *grpdescstr[NUM_GRPDESC_TYPES] = {
188   "UNDEFINED - 0",
189   "Default 768-bit MODP group",
190   "Alternate 1024-bit MODP group",
191   "EC2N group on GP[2^155] group",
192   "EC2N group on GP[2^185] group",
193   "Reserved to IANA",
194   "EC2N group over GF[2^163]",
195   "EC2N group over GF[2^163]",
196   "EC2N group over GF[2^283]",
197   "EC2N group over GF[2^283]",
198   "EC2N group over GF[2^409]",
199   "EC2N group over GF[2^409]",
200   "EC2N group over GF[2^571]",
201   "EC2N group over GF[2^571]"
202 };
203
204 struct isakmp_hdr {
205   guint8        icookie[8];
206   guint8        rcookie[8];
207   guint8        next_payload;
208   guint8        version;
209   guint8        exch_type;
210   guint8        flags;
211 #define E_FLAG          0x01
212 #define C_FLAG          0x02
213 #define A_FLAG          0x04
214   guint32       message_id;
215   guint32       length;
216 };
217
218 struct udp_encap_hdr {
219   guint8        non_esp_marker[4];
220   guint32       esp_SPI;
221 };
222
223 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
224     guint8 *, guint16 *, proto_tree *);
225
226 static void dissect_sa(tvbuff_t *, int, int, proto_tree *, int);
227 static void dissect_proposal(tvbuff_t *, int, int, proto_tree *, int);
228 static void dissect_transform(tvbuff_t *, int, int, proto_tree *, int);
229 static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *, int);
230 static void dissect_id(tvbuff_t *, int, int, proto_tree *, int);
231 static void dissect_cert(tvbuff_t *, int, int, proto_tree *, int);
232 static void dissect_certreq(tvbuff_t *, int, int, proto_tree *, int);
233 static void dissect_hash(tvbuff_t *, int, int, proto_tree *, int);
234 static void dissect_sig(tvbuff_t *, int, int, proto_tree *, int);
235 static void dissect_nonce(tvbuff_t *, int, int, proto_tree *, int);
236 static void dissect_notif(tvbuff_t *, int, int, proto_tree *, int);
237 static void dissect_delete(tvbuff_t *, int, int, proto_tree *, int);
238 static void dissect_vid(tvbuff_t *, int, int, proto_tree *, int);
239 static void dissect_config(tvbuff_t *, int, int, proto_tree *, int);
240
241 static const char *payloadtype2str(guint8);
242 static const char *exchtype2str(guint8);
243 static const char *doitype2str(guint32);
244 static const char *msgtype2str(guint16);
245 static const char *situation2str(guint32);
246 static const char *value2str(int, guint16, guint16);
247 static const char *attrtype2str(guint8);
248 static const char *cfgattrident2str(guint16);
249 static const char *certtype2str(guint8);
250
251 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
252
253 #define LOAD_TYPE_NONE          0       /* payload type for None */
254 #define LOAD_TYPE_PROPOSAL      2       /* payload type for Proposal */
255 #define LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
256 #define NUM_LOAD_TYPES          17
257 #define loadtype2str(t) \
258   ((t < NUM_LOAD_TYPES) ? strfuncs[t].str : "Unknown payload type")
259
260 static struct strfunc {
261   const char *  str;
262   void          (*func)(tvbuff_t *, int, int, proto_tree *, int);
263 } strfuncs[NUM_LOAD_TYPES] = {
264   {"NONE",                      NULL              },
265   {"Security Association",      dissect_sa        },
266   {"Proposal",                  dissect_proposal  },
267   {"Transform",                 dissect_transform },
268   {"Key Exchange",              dissect_key_exch  },
269   {"Identification",            dissect_id        },
270   {"Certificate",               dissect_cert      },
271   {"Certificate Request",       dissect_certreq   },
272   {"Hash",                      dissect_hash      },
273   {"Signature",                 dissect_sig       },
274   {"Nonce",                     dissect_nonce     },
275   {"Notification",              dissect_notif     },
276   {"Delete",                    dissect_delete    },
277   {"Vendor ID",                 dissect_vid       },
278   {"Attrib",                    dissect_config    },
279   {"NAT-Discovery",             NULL              }, /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
280   {"NAT-Original Address",      NULL              }  /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
281 };
282
283 #define VID_LEN 16
284 #define VID_MS_LEN 20
285 static const guint8 VID_MS_W2K_WXP[VID_MS_LEN] = {0x1E, 0x2B, 0x51, 0x69, 0x5, 0x99, 0x1C, 0x7D, 0x7C, 0x96, 0xFC, 0xBF, 0xB5, 0x87, 0xE4, 0x61, 0x0, 0x0, 0x0, 0x2}; /* according to http://www.microsoft.com/technet/treeview/default.asp?url=/technet/columns/cableguy/cg0602.asp */
286
287 #define VID_CP_LEN 20
288 static const guint8 VID_CP[VID_CP_LEN] = {0xF4, 0xED, 0x19, 0xE0, 0xC1, 0x14, 0xEB, 0x51, 0x6F, 0xAA, 0xAC, 0x0E, 0xE3, 0x7D, 0xAF, 0x28, 0x7, 0xB4, 0x38, 0x1F};
289
290 static const guint8 VID_CYBERGUARD[VID_LEN] = {0x9A, 0xA1, 0xF3, 0xB4, 0x34, 0x72, 0xA4, 0x5D, 0x5F, 0x50, 0x6A, 0xEB, 0x26, 0xC, 0xF2, 0x14};
291
292 static const guint8 VID_SAFENET[VID_LEN] = {0x44, 0x85, 0x15, 0x2D, 0x18, 0xB6, 0xBB, 0xCD, 0x0B, 0xE8, 0xA8, 0x46, 0x95, 0x79, 0xDD, 0xCC};
293
294 static const guint8 VID_draft_ietf_ipsec_nat_t_ike_03[VID_LEN] = {0x7D, 0x94, 0x19, 0xA6, 0x53, 0x10, 0xCA, 0x6F, 0x2C, 0x17, 0x9D, 0x92, 0x15, 0x52, 0x9d, 0x56}; /* according to http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-03.txt */
295
296 /* 
297 *  Seen in Netscreen. Suppose to be ASCII HeartBeat_Notify - but I don't know the rest yet. I suspect it then proceeds with
298 *  8k10, which means every 8K (?), and version 1.0 of the protocol (?). I won't add it to the code, until I know what it really
299 *  means. ykaul-at-netvision.net.il
300 */
301 static const guint8 VID_HeartBeat_Notify[VID_LEN] = {0x48, 0x65, 0x61, 0x72, 0x74, 0x42, 0x65, 0x61, 0x74, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79}; 
302
303 static dissector_handle_t esp_handle;
304 static dissector_handle_t ah_handle;
305
306 static void
307 dissect_payloads(tvbuff_t *tvb, proto_tree *tree, guint8 initial_payload,
308                  int offset, int length)
309 {
310   guint8 payload, next_payload;
311   guint16               payload_length;
312   proto_tree *          ntree;
313
314   for (payload = initial_payload; length != 0; payload = next_payload) {
315     if (payload == LOAD_TYPE_NONE) {
316       /*
317        * What?  There's more stuff in this chunk of data, but the
318        * previous payload had a "next payload" type of None?
319        */
320       proto_tree_add_text(tree, tvb, offset, length,
321                           "Extra data: %s",
322                           tvb_bytes_to_str(tvb, offset, length));
323       break;
324     }
325     ntree = dissect_payload_header(tvb, offset, length, payload,
326       &next_payload, &payload_length, tree);
327     if (ntree == NULL)
328       break;
329     if (payload_length >= 4) {  /* XXX = > 4? */
330       if (payload < NUM_LOAD_TYPES) {
331         (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
332                                   -1);
333       }
334       else {
335         proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
336             "Payload");
337       }
338     }
339     else {
340         proto_tree_add_text(ntree, tvb, offset + 4, 0,
341             "Payload (bogus, length is %u, must be at least 4)",
342             payload_length);
343         payload_length = 4;
344     }
345     offset += payload_length;
346     length -= payload_length;
347   }
348 }
349
350 static void
351 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
352 {
353   int                   offset = 0;
354   struct isakmp_hdr     hdr;
355   proto_item *          ti;
356   proto_tree *          isakmp_tree = NULL;
357   struct udp_encap_hdr  encap_hdr;
358   guint32               len;
359   static const guint8   non_esp_marker[4] = { 0, 0, 0, 0 };
360   tvbuff_t *            next_tvb;
361
362   if (check_col(pinfo->cinfo, COL_PROTOCOL))
363     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISAKMP");
364   if (check_col(pinfo->cinfo, COL_INFO))
365     col_clear(pinfo->cinfo, COL_INFO);
366
367   hdr.length = tvb_get_ntohl(tvb, offset + sizeof(hdr) - sizeof(hdr.length));
368
369   if (tree) {
370     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, hdr.length, FALSE);
371     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
372   }
373
374   tvb_memcpy(tvb, (guint8 *)&encap_hdr, 0, sizeof(encap_hdr));
375
376   if (encap_hdr.non_esp_marker[0] == 0xFF) {
377     if (check_col(pinfo->cinfo, COL_INFO))
378       col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - NAT Keepalive");
379     return;
380   }
381   if (memcmp(encap_hdr.non_esp_marker,non_esp_marker,4) == 0) {
382     if (check_col(pinfo->cinfo, COL_INFO))
383           col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - ESP");
384     if (tree)
385       proto_tree_add_text(isakmp_tree, tvb, offset,
386                           sizeof(encap_hdr.non_esp_marker),
387                           "Non-ESP-Marker");
388     offset += sizeof(encap_hdr.non_esp_marker);
389     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
390     call_dissector(esp_handle, next_tvb, pinfo, tree);
391     return;
392   }
393   hdr.exch_type = tvb_get_guint8(tvb, sizeof(hdr.icookie) + sizeof(hdr.rcookie) + sizeof(hdr.next_payload) + sizeof(hdr.version));
394   if (check_col(pinfo->cinfo, COL_INFO))
395     col_add_str(pinfo->cinfo, COL_INFO, exchtype2str(hdr.exch_type));
396
397   if (tree) {
398     tvb_memcpy(tvb, (guint8 *)&hdr.icookie, offset, sizeof(hdr.icookie));
399     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.icookie),
400                         "Initiator cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.icookie)));
401     offset += sizeof(hdr.icookie);
402
403     tvb_memcpy(tvb, (guint8 *)&hdr.rcookie, offset, sizeof(hdr.rcookie));
404     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.rcookie),
405                         "Responder cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.rcookie)));
406     offset += sizeof(hdr.rcookie);
407
408     hdr.next_payload = tvb_get_guint8(tvb, offset);
409     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.next_payload),
410                         "Next payload: %s (%u)",
411                         payloadtype2str(hdr.next_payload), hdr.next_payload);
412     offset += sizeof(hdr.next_payload);
413
414     hdr.version = tvb_get_guint8(tvb, offset);
415     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.version),
416                         "Version: %u.%u",
417                         hi_nibble(hdr.version), lo_nibble(hdr.version));
418     offset += sizeof(hdr.version);
419
420     hdr.exch_type = tvb_get_guint8(tvb, offset);
421     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.exch_type),
422                         "Exchange type: %s (%u)",
423                         exchtype2str(hdr.exch_type), hdr.exch_type);
424     offset += sizeof(hdr.exch_type);
425
426     {
427       proto_item *      fti;
428       proto_tree *      ftree;
429
430       hdr.flags = tvb_get_guint8(tvb, offset);
431       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.flags), "Flags");
432       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
433
434       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
435                           decode_boolean_bitfield(hdr.flags, E_FLAG, sizeof(hdr.flags)*8,
436                                                   "Encryption", "No encryption"));
437       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
438                           decode_boolean_bitfield(hdr.flags, C_FLAG, sizeof(hdr.flags)*8,
439                                                   "Commit", "No commit"));
440       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
441                           decode_boolean_bitfield(hdr.flags, A_FLAG, sizeof(hdr.flags)*8,
442                                                   "Authentication", "No authentication"));
443       offset += sizeof(hdr.flags);
444     }
445
446     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.message_id),
447         "Message ID: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.message_id)));
448     offset += sizeof(hdr.message_id);
449
450     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.length),
451                         "Length: %u", hdr.length);
452     offset += sizeof(hdr.length);
453
454     len = hdr.length - sizeof(hdr);
455
456     if (hdr.flags & E_FLAG) {
457       if (len && isakmp_tree) {
458         proto_tree_add_text(isakmp_tree, tvb, offset, len,
459                         "Encrypted payload (%d byte%s)",
460                         len, plurality(len, "", "s"));
461       }
462     } else
463       dissect_payloads(tvb, isakmp_tree, hdr.next_payload, offset, len);
464   }
465 }
466
467 static proto_tree *
468 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
469     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
470 {
471   guint8                next_payload;
472   guint16               payload_length;
473   proto_item *          ti;
474   proto_tree *          ntree;
475
476   if (length < 4) {
477     proto_tree_add_text(tree, tvb, offset, length,
478           "Not enough room in payload for all transforms");
479     return NULL;
480   }
481   next_payload = tvb_get_guint8(tvb, offset);
482   payload_length = tvb_get_ntohs(tvb, offset + 2);
483
484   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
485             "%s payload", loadtype2str(payload));
486   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
487
488   proto_tree_add_text(ntree, tvb, offset, 1,
489                       "Next payload: %s (%u)",
490                       payloadtype2str(next_payload), next_payload);
491   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
492
493   *next_payload_p = next_payload;
494   *payload_length_p = payload_length;
495   return ntree;
496 }
497
498 static void
499 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
500     int unused _U_)
501 {
502   guint32               doi;
503   guint32               situation;
504
505   if (length < 4) {
506     proto_tree_add_text(tree, tvb, offset, length,
507                         "DOI %s (length is %u, should be >= 4)",
508                         tvb_bytes_to_str(tvb, offset, length), length);
509     return;
510   }
511   doi = tvb_get_ntohl(tvb, offset);
512   proto_tree_add_text(tree, tvb, offset, 4,
513                       "Domain of interpretation: %s (%u)",
514                       doitype2str(doi), doi);
515   offset += 4;
516   length -= 4;
517
518   if (doi == 1) {
519     /* IPSEC */
520     if (length < 4) {
521       proto_tree_add_text(tree, tvb, offset, length,
522                           "Situation: %s (length is %u, should be >= 4)",
523                           tvb_bytes_to_str(tvb, offset, length), length);
524       return;
525     }
526     situation = tvb_get_ntohl(tvb, offset);
527     proto_tree_add_text(tree, tvb, offset, 4,
528                         "Situation: %s (%u)",
529                         situation2str(situation), situation);
530     offset += 4;
531     length -= 4;
532
533     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length);
534   } else {
535     /* Unknown */
536     proto_tree_add_text(tree, tvb, offset, length,
537                         "Situation: %s",
538                         tvb_bytes_to_str(tvb, offset, length));
539   }
540 }
541
542 static void
543 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
544     int unused _U_)
545 {
546   guint8                protocol_id;
547   guint8                spi_size;
548   guint8                num_transforms;
549   guint8                next_payload;
550   guint16               payload_length;
551   proto_tree *          ntree;
552   guint8                proposal_num;
553
554   proposal_num = tvb_get_guint8(tvb, offset);
555
556   proto_item_append_text(tree, " # %d",proposal_num);
557   proto_tree_add_text(tree, tvb, offset, 1,
558                       "Proposal number: %u", proposal_num);
559   offset += 1;
560   length -= 1;
561
562   protocol_id = tvb_get_guint8(tvb, offset);
563   proto_tree_add_text(tree, tvb, offset, 1,
564                       "Protocol ID: %s (%u)",
565                       proto2str(protocol_id), protocol_id);
566   offset += 1;
567   length -= 1;
568
569   spi_size = tvb_get_guint8(tvb, offset);
570   proto_tree_add_text(tree, tvb, offset, 1,
571                       "SPI size: %u", spi_size);
572   offset += 1;
573   length -= 1;
574
575   num_transforms = tvb_get_guint8(tvb, offset);
576   proto_tree_add_text(tree, tvb, offset, 1,
577                       "Number of transforms: %u", num_transforms);
578   offset += 1;
579   length -= 1;
580
581   if (spi_size) {
582     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI: %s",
583                         tvb_bytes_to_str(tvb, offset, spi_size));
584     offset += spi_size;
585     length -= spi_size;
586   }
587
588   while (num_transforms > 0) {
589     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
590       &next_payload, &payload_length, tree);
591     if (ntree == NULL)
592       break;
593     if (length < payload_length) {
594       proto_tree_add_text(tree, tvb, offset + 4, length,
595           "Not enough room in payload for all transforms");
596       break;
597     }
598     if (payload_length >= 4)
599       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
600     else
601       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
602     offset += payload_length;
603     length -= payload_length;
604     num_transforms--;
605   }
606 }
607
608 static void
609 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
610     int protocol_id)
611 {
612   guint8                transform_id;
613   guint8                transform_num;
614
615   transform_num = tvb_get_guint8(tvb, offset);
616   proto_item_append_text(tree," # %d",transform_num);
617   proto_tree_add_text(tree, tvb, offset, 1,
618                       "Transform number: %u", transform_num);
619   offset += 1;
620   length -= 1;
621
622   transform_id = tvb_get_guint8(tvb, offset);
623   switch (protocol_id) {
624   default:
625     proto_tree_add_text(tree, tvb, offset, 1,
626                         "Transform ID: %u", transform_id);
627     break;
628   case 1:       /* ISAKMP */
629     proto_tree_add_text(tree, tvb, offset, 1,
630                         "Transform ID: %s (%u)",
631                         trans2str(transform_id), transform_id);
632     break;
633   case 2:       /* AH */
634     proto_tree_add_text(tree, tvb, offset, 1,
635                         "Transform ID: %s (%u)",
636                         ah_trans2str(transform_id), transform_id);
637     break;
638   case 3:       /* ESP */
639     proto_tree_add_text(tree, tvb, offset, 1,
640                         "Transform ID: %s (%u)",
641                         esp_trans2str(transform_id), transform_id);
642     break;
643   case 4:       /* IPCOMP */
644     proto_tree_add_text(tree, tvb, offset, 1,
645                         "Transform ID: %s (%u)",
646                         ipcomp_trans2str(transform_id), transform_id);
647     break;
648   }
649   offset += 3;
650   length -= 3;
651
652   while (length>0) {
653     const char *str;
654     int ike_phase1 = 0;
655     guint16 aft     = tvb_get_ntohs(tvb, offset);
656     guint16 type    = aft & 0x7fff;
657     guint16 len;
658     guint32 val;
659     guint pack_len;
660
661     if (protocol_id == 1 && transform_id == 1) {
662       ike_phase1 = 1;
663       str = p1_atttype2str(type);
664     }
665     else {
666       str = atttype2str(type);
667     }
668
669     if (aft & 0x8000) {
670       val = tvb_get_ntohs(tvb, offset + 2);
671       proto_tree_add_text(tree, tvb, offset, 4,
672                           "%s (%u): %s (%u)",
673                           str, type,
674                           value2str(ike_phase1, type, val), val);
675       offset += 4;
676       length -= 4;
677     }
678     else {
679       len = tvb_get_ntohs(tvb, offset + 2);
680       pack_len = 4 + len;
681       if (!get_num(tvb, offset + 4, len, &val)) {
682         proto_tree_add_text(tree, tvb, offset, pack_len,
683                             "%s (%u): <too big (%u bytes)>",
684                             str, type, len);
685       } else {
686         proto_tree_add_text(tree, tvb, offset, pack_len,
687                             "%s (%u): %s (%u)",
688                             str, type,
689                             value2str(ike_phase1, type, val), val);
690       }
691       offset += pack_len;
692       length -= pack_len;
693     }
694   }
695 }
696
697 static void
698 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
699     int unused _U_)
700 {
701   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
702 }
703
704 static void
705 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
706     int unused _U_)
707 {
708   guint8                id_type;
709   guint8                protocol_id;
710   guint16               port;
711
712   id_type = tvb_get_guint8(tvb, offset);
713   proto_tree_add_text(tree, tvb, offset, 1,
714                       "ID type: %s (%u)", id2str(id_type), id_type);
715   offset += 1;
716   length -= 1;
717
718   protocol_id = tvb_get_guint8(tvb, offset);
719   if (protocol_id == 0) {
720     proto_tree_add_text(tree, tvb, offset, 1,
721                         "Protocol ID: Unused");
722   } else {
723     proto_tree_add_text(tree, tvb, offset, 1,
724                         "Protocol ID: %s (%u)",
725                         ipprotostr(protocol_id), protocol_id);
726   }
727   offset += 1;
728   length -= 1;
729
730   port = tvb_get_ntohs(tvb, offset);
731   if (port == 0)
732     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
733   else
734     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
735   offset += 2;
736   length -= 2;
737
738   switch (id_type) {
739     case 1:
740       proto_tree_add_text(tree, tvb, offset, length,
741                           "Identification data: %s",
742                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
743       break;
744     case 2:
745     case 3:
746       proto_tree_add_text(tree, tvb, offset, length,
747                           "Identification data: %.*s", length,
748                           tvb_get_ptr(tvb, offset, length));
749       break;
750     case 4:
751       proto_tree_add_text(tree, tvb, offset, length,
752                           "Identification data: %s/%s",
753                           ip_to_str(tvb_get_ptr(tvb, offset, 4)),
754                           ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
755       break;
756     default:
757       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
758       break;
759   }
760 }
761
762 static void
763 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
764     int unused _U_)
765 {
766   guint8                cert_enc;
767
768   cert_enc = tvb_get_guint8(tvb, offset);
769   proto_tree_add_text(tree, tvb, offset, 1,
770                       "Certificate encoding: %u - %s",
771                       cert_enc, certtype2str(cert_enc));
772   offset += 1;
773   length -= 1;
774
775   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
776 }
777
778 static void
779 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
780     int unused _U_)
781 {
782   guint8                cert_type;
783
784   cert_type = tvb_get_guint8(tvb, offset);
785   proto_tree_add_text(tree, tvb, offset, 1,
786                       "Certificate type: %u - %s",
787                       cert_type, certtype2str(cert_type));
788   offset += 1;
789   length -= 1;
790
791   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
792 }
793
794 static void
795 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
796     int unused _U_)
797 {
798   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
799 }
800
801 static void
802 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
803     int unused _U_)
804 {
805   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
806 }
807
808 static void
809 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
810     int unused _U_)
811 {
812   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
813 }
814
815 static void
816 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
817     int unused _U_)
818 {
819   guint32               doi;
820   guint8                protocol_id;
821   guint8                spi_size;
822   guint16               msgtype;
823
824   doi = tvb_get_ntohl(tvb, offset);
825   proto_tree_add_text(tree, tvb, offset, 4,
826                       "Domain of Interpretation: %s (%u)",
827                       doitype2str(doi), doi);
828   offset += 4;
829   length -= 4;
830
831   protocol_id = tvb_get_guint8(tvb, offset);
832   proto_tree_add_text(tree, tvb, offset, 1,
833                       "Protocol ID: %s (%u)",
834                       proto2str(protocol_id), protocol_id);
835   offset += 1;
836   length -= 1;
837
838   spi_size = tvb_get_guint8(tvb, offset);
839   proto_tree_add_text(tree, tvb, offset, 1,
840                       "SPI size: %u", spi_size);
841   offset += 1;
842   length -= 1;
843
844   msgtype = tvb_get_ntohs(tvb, offset);
845   proto_tree_add_text(tree, tvb, offset, 2,
846                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
847   offset += 2;
848   length -= 2;
849
850   if (spi_size) {
851     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
852     offset += spi_size;
853     length -= spi_size;
854   }
855
856   if (length > 0)
857     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
858 }
859
860 static void
861 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
862     int unused _U_)
863 {
864   guint32               doi;
865   guint8                protocol_id;
866   guint8                spi_size;
867   guint16               num_spis;
868   guint16               i;
869
870   doi = tvb_get_ntohl(tvb, offset);
871   proto_tree_add_text(tree, tvb, offset, 4,
872                       "Domain of Interpretation: %s (%u)",
873                       doitype2str(doi), doi);
874   offset += 4;
875   length -= 4;
876
877   protocol_id = tvb_get_guint8(tvb, offset);
878   proto_tree_add_text(tree, tvb, offset, 1,
879                       "Protocol ID: %s (%u)",
880                       proto2str(protocol_id), protocol_id);
881   offset += 1;
882   length -= 1;
883
884   spi_size = tvb_get_guint8(tvb, offset);
885   proto_tree_add_text(tree, tvb, offset, 1,
886                       "SPI size: %u", spi_size);
887   offset += 1;
888   length -= 1;
889
890   num_spis = tvb_get_ntohs(tvb, offset);
891   proto_tree_add_text(tree, tvb, offset, 2,
892                       "Number of SPIs: %u", num_spis);
893   offset += 2;
894   length -= 2;
895
896   for (i = 0; i < num_spis; ++i) {
897     if (length < spi_size) {
898       proto_tree_add_text(tree, tvb, offset, length,
899           "Not enough room in payload for all SPI's");
900       break;
901     }
902     proto_tree_add_text(tree, tvb, offset, spi_size,
903                         "SPI (%d)", i);
904     offset += spi_size;
905     length -= spi_size;
906   }
907 }
908
909 static void
910 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
911     int unused _U_)
912 {
913   guint32 CPproduct, CPversion;
914   const guint8 * pVID;
915   proto_item * pt;
916   proto_tree * ntree;
917   pVID = tvb_get_ptr(tvb, offset, length);
918   pt = proto_tree_add_text(tree, tvb, offset, length, "Vendor ID: ");
919   if (memcmp(pVID, VID_MS_W2K_WXP, isakmp_min(VID_MS_LEN, length)) == 0)
920         proto_item_append_text(pt, "Microsoft Win2K/WinXP");
921   else
922   if (memcmp(pVID, VID_CP, isakmp_min(VID_CP_LEN, length)) == 0)
923   {
924         proto_item_append_text(pt, "Check Point");
925         offset += VID_CP_LEN;
926         CPproduct = tvb_get_ntohl(tvb, offset);
927         ntree = proto_item_add_subtree(pt, ett_isakmp_payload);
928         pt = proto_tree_add_text(ntree, tvb, offset, sizeof(CPproduct), "Check Point Product: ");
929         switch (CPproduct) {
930                 case 1: proto_item_append_text(pt, "VPN-1");
931                         break;
932                 case 2: proto_item_append_text(pt, "SecuRemote/SecureClient");
933                         break;
934                 default: proto_item_append_text(pt, "Unknown CP product!");
935                         break;
936         }
937         offset += sizeof(CPproduct);
938         CPversion = tvb_get_ntohl(tvb, offset);
939         pt = proto_tree_add_text(ntree, tvb, offset, length, "Version: ");
940         switch (CPversion) {
941                 case 2: proto_item_append_text(pt, "4.1");
942                         break;
943                 case 3: proto_item_append_text(pt, "4.1 SP-1");
944                         break;
945                 case 4002: proto_item_append_text(pt, "4.1 (SP-2 or above)");
946                         break;
947                 case 5000: proto_item_append_text(pt, "NG");
948                         break;
949                 case 5001: proto_item_append_text(pt, "NG Feature Pack 1");
950                         break;
951                 case 5002: proto_item_append_text(pt, "NG Feature Pack 2");
952                         break;
953                 case 5003: proto_item_append_text(pt, "NG Feature Pack 3");
954                         break;
955                 default: proto_item_append_text(pt, " Uknown CP version!");
956                         break;
957         }
958   }
959   else
960   if (memcmp(pVID, VID_CYBERGUARD, isakmp_min(VID_LEN, length)) == 0)
961         proto_item_append_text(pt, "Cyber Guard");
962   else
963   if (memcmp(pVID, VID_SAFENET, isakmp_min(VID_LEN, length)) == 0)
964         proto_item_append_text(pt, "SafeNet");
965   else
966   if (memcmp(pVID,  VID_draft_ietf_ipsec_nat_t_ike_03, isakmp_min(VID_LEN, length)) == 0)
967         proto_item_append_text(pt, "draft-ietf-ipsec-nat-t-ike-03");
968   else
969         proto_item_append_text(pt, "unknown vendor ID: 0x%s",tvb_bytes_to_str(tvb, offset, length));
970 }
971
972 static void
973 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
974     int unused _U_)
975 {
976   guint8                type;
977
978   type = tvb_get_guint8(tvb, offset);
979   proto_tree_add_text(tree, tvb, offset, 1,
980                       "Type %s (%u)",attrtype2str(type),type);
981
982   offset += 2;
983   length -= 2;
984
985   proto_tree_add_text(tree, tvb, offset, 2,
986                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
987   offset += 2;
988   length -= 2;
989
990   while(length>0) {
991     guint16 aft     = tvb_get_ntohs(tvb, offset);
992     guint16 type    = aft & 0x7fff;
993     guint16 len;
994     guint32 val;
995     guint pack_len;
996
997     if (aft & 0x8000) {
998       val = tvb_get_ntohs(tvb, offset + 2);
999       proto_tree_add_text(tree, tvb, offset, 4,
1000                           "%s (%u)", cfgattrident2str(type), val);
1001       offset += 4;
1002       length -= 4;
1003     }
1004     else {
1005       len = tvb_get_ntohs(tvb, offset + 2);
1006       pack_len = 4 + len;
1007       if (!get_num(tvb, offset + 4, len, &val)) {
1008         proto_tree_add_text(tree, tvb, offset, pack_len,
1009                             "%s: <too big (%u bytes)>",
1010                             cfgattrident2str(type), len);
1011       } else {
1012         proto_tree_add_text(tree, tvb, offset, 4,
1013                             "%s (%ue)", cfgattrident2str(type),
1014                             val);
1015       }
1016       offset += pack_len;
1017       length -= pack_len;
1018     }
1019   }
1020 }
1021
1022 static const char *
1023 payloadtype2str(guint8 type) {
1024
1025   if (type < NUM_LOAD_TYPES) return strfuncs[type].str;
1026   if (type < 128)            return "RESERVED";
1027   if (type < 256)            return "Private USE";
1028
1029   return "Huh? You should never see this! Shame on you!";
1030 }
1031
1032 static const char *
1033 exchtype2str(guint8 type) {
1034
1035 #define NUM_EXCHSTRS    7
1036   static const char * exchstrs[NUM_EXCHSTRS] = {
1037     "NONE",
1038     "Base",
1039     "Identity Protection (Main Mode)",
1040     "Authentication Only",
1041     "Aggressive",
1042     "Informational",
1043     "Transaction (Config Mode)"
1044   };
1045
1046   if (type < NUM_EXCHSTRS) return exchstrs[type];
1047   if (type < 32)           return "ISAKMP Future Use";
1048   switch (type) {
1049   case 32:
1050     return "Quick Mode";
1051   case 33:
1052     return "New Group Mode";
1053   }
1054   if (type < 240)          return "DOI Specific Use";
1055   if (type < 256)          return "Private Use";
1056
1057   return "Huh? You should never see this! Shame on you!";
1058 }
1059
1060 static const char *
1061 doitype2str(guint32 type) {
1062   if (type == 1) return "IPSEC";
1063   return "Unknown DOI Type";
1064 }
1065
1066 static const char *
1067 msgtype2str(guint16 type) {
1068
1069 #define NUM_PREDEFINED  31
1070   static const char *msgs[NUM_PREDEFINED] = {
1071     "<UNKNOWN>",
1072     "INVALID-PAYLOAD-TYPE",
1073     "DOI-NOT-SUPPORTED",
1074     "SITUATION-NOT-SUPPORTED",
1075     "INVALID-COOKIE",
1076     "INVALID-MAJOR-VERSION",
1077     "INVALID-MINOR-VERSION",
1078     "INVALID-EXCHANGE-TYPE",
1079     "INVALID-FLAGS",
1080     "INVALID-MESSAGE-ID",
1081     "INVALID-PROTOCOL-ID",
1082     "INVALID-SPI",
1083     "INVALID-TRANSFORM-ID",
1084     "ATTRIBUTES-NOT-SUPPORTED",
1085     "NO-PROPOSAL-CHOSEN",
1086     "BAD-PROPOSAL-SYNTAX",
1087     "PAYLOAD-MALFORMED",
1088     "INVALID-KEY-INFORMATION",
1089     "INVALID-ID-INFORMATION",
1090     "INVALID-CERT-ENCODING",
1091     "INVALID-CERTIFICATE",
1092     "CERT-TYPE-UNSUPPORTED",
1093     "INVALID-CERT-AUTHORITY",
1094     "INVALID-HASH-INFORMATION",
1095     "AUTHENTICATION-FAILED",
1096     "INVALID-SIGNATURE",
1097     "ADDRESS-NOTIFICATION",
1098     "NOTIFY-SA-LIFETIME",
1099     "CERTIFICATE-UNAVAILABLE",
1100     "UNSUPPORTED-EXCHANGE-TYPE",
1101     "UNEQUAL-PAYLOAD-LENGTHS"
1102   };
1103
1104   if (type < NUM_PREDEFINED) return msgs[type];
1105   if (type < 8192)           return "RESERVED (Future Use)";
1106   if (type < 16384)          return "Private Use";
1107   if (type < 16385)          return "CONNECTED";
1108   if (type < 24576)          return "RESERVED (Future Use) - status";
1109   if (type < 24577)          return "RESPONDER-LIFETIME";
1110   if (type < 24578)          return "REPLAY-STATUS";
1111   if (type < 24579)          return "INITIAL-CONTACT";
1112   if (type < 32768)          return "DOI-specific codes";
1113   if (type < 40960)          return "Private Use - status";
1114   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
1115
1116   return "Huh? You should never see this! Shame on you!";
1117 }
1118
1119 static const char *
1120 situation2str(guint32 type) {
1121
1122 #define SIT_MSG_NUM     1024
1123 #define SIT_IDENTITY    0x01
1124 #define SIT_SECRECY     0x02
1125 #define SIT_INTEGRITY   0x04
1126
1127   static char   msg[SIT_MSG_NUM];
1128   int           n = 0;
1129   char *        sep = "";
1130   int           ret;
1131
1132   if (type & SIT_IDENTITY) {
1133     ret = snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
1134     if (ret == -1) {
1135       /* Some versions of snprintf return -1 if they'd truncate the output. */
1136       return msg;
1137     }
1138     n += ret;
1139     sep = " & ";
1140   }
1141   if (type & SIT_SECRECY) {
1142     if (n >= SIT_MSG_NUM) {
1143       /* No more room. */
1144       return msg;
1145     }
1146     ret = snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
1147     if (ret == -1) {
1148       /* Some versions of snprintf return -1 if they'd truncate the output. */
1149       return msg;
1150     }
1151     n += ret;
1152     sep = " & ";
1153   }
1154   if (type & SIT_INTEGRITY) {
1155     if (n >= SIT_MSG_NUM) {
1156       /* No more room. */
1157       return msg;
1158     }
1159     ret = snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
1160     if (ret == -1) {
1161       /* Some versions of snprintf return -1 if they'd truncate the output. */
1162       return msg;
1163     }
1164     n += ret;
1165     sep = " & ";
1166   }
1167
1168   return msg;
1169 }
1170
1171 static const char *
1172 value2str(int ike_p1, guint16 att_type, guint16 value) {
1173
1174   if (value == 0) return "RESERVED";
1175
1176   if (!ike_p1) {
1177   switch (att_type) {
1178     case 1:
1179       switch (value) {
1180         case 0: return "RESERVED";
1181         case 1:  return "Seconds";
1182         case 2:  return "Kilobytes";
1183         default: return "UNKNOWN-SA-VALUE";
1184       }
1185     case 2:
1186       return "Duration-Value";
1187     case 3:
1188       return "Group-Value";
1189     case 4:
1190       switch (value) {
1191         case 0:  return "RESERVED";
1192         case 1:  return "Tunnel";
1193         case 2:  return "Transport";
1194         case 3:  return "UDP-Encapsulated-Tunnel"; /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
1195         case 4:  return "UDP-Encapsulated-Transport"; /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
1196         case 61440: return "Check Point IPSec UDP Encapsulation";
1197         case 61443: return "UDP-Encapsulated-Tunnel (draft)";
1198         case 61444: return "UDP-Encapsulated-Transport (draft)";
1199         default: return "UNKNOWN-ENCAPSULATION-VALUE";
1200       }
1201     case 5:
1202       switch (value) {
1203         case 0:  return "RESERVED";
1204         case 1:  return "HMAC-MD5";
1205         case 2:  return "HMAC-SHA";
1206         case 3:  return "DES-MAC";
1207         case 4:  return "KPDK";
1208         case 5:  return "HMAC-SHA2-256";
1209         case 6:  return "HMAC-SHA2-384";
1210         case 7:  return "HMAC-SHA2-512";
1211         default: return "UNKNOWN-AUTHENTICATION-VALUE";
1212       }
1213     case 6:
1214       return "Key-Length";
1215     case 7:
1216       return "Key-Rounds";
1217     case 8:
1218       return "Compress-Dictionary-size";
1219     case 9:
1220       return "Compress Private Algorithm";
1221     default: return "UNKNOWN-ATTRIBUTE-TYPE";
1222   }
1223   }
1224   else {
1225     switch (att_type) {
1226       case 1:
1227         switch (value) {
1228           case 1:  return "DES-CBC";
1229           case 2:  return "IDEA-CBC";
1230           case 3:  return "BLOWFISH-CBC";
1231           case 4:  return "RC5-R16-B64-CBC";
1232           case 5:  return "3DES-CBC";
1233           case 6:  return "CAST-CBC";
1234           case 7:  return "AES-CBC";
1235           default: return "UNKNOWN-ENCRYPTION-ALG";
1236         }
1237       case 2:
1238         switch (value) {
1239           case 1:  return "MD5";
1240           case 2:  return "SHA";
1241           case 3:  return "TIGER";
1242           case 4:  return "SHA2-256";
1243           case 5:  return "SHA2-384";
1244           case 6:  return "SHA2-512";
1245           default: return "UNKNOWN-HASH-ALG";
1246         }
1247       case 3:
1248         switch (value) {
1249           case 1:  return "PSK";
1250           case 2:  return "DSS-SIG";
1251           case 3:  return "RSA-SIG";
1252           case 4:  return "RSA-ENC";
1253           case 5:  return "RSA-Revised-ENC";
1254           case 6:  return "Encryption with El-Gamal";
1255           case 7:  return "Revised encryption with El-Gamal";
1256           case 8:  return "ECDSA signatures";
1257           case 64221: return "HybridInitRSA";
1258           case 64222: return "HybridRespRSA";
1259           case 64223: return "HybridInitDSS";
1260           case 64224: return "HybridRespDSS";
1261           case 65001: return "XAUTHInitPreShared";
1262           case 65002: return "XAUTHRespPreShared";
1263           case 65003: return "XAUTHInitDSS";
1264           case 65004: return "XAUTHRespDSS";
1265           case 65005: return "XAUTHInitRSA";
1266           case 65006: return "XAUTHRespRSA";
1267           case 65007: return "XAUTHInitRSAEncryption";
1268           case 65008: return "XAUTHRespRSAEncryption";
1269           case 65009: return "XAUTHInitRSARevisedEncryption";
1270           case 65010: return "XAUTHRespRSARevisedEncryption";
1271           default: return "UNKNOWN-AUTH-METHOD";
1272         }
1273       case 4: return grpdesc2str(value);
1274       case 6:
1275       case 7:
1276       case 8:
1277       case 9:
1278       case 10:
1279       case 16:
1280         return "Group-Value";
1281       case 5:
1282         switch (value) {
1283           case 1:  return "MODP";
1284           case 2:  return "ECP";
1285           case 3:  return "EC2N";
1286           default: return "UNKNOWN-GROUPT-TYPE";
1287         }
1288       case 11:
1289         switch (value) {
1290           case 1:  return "Seconds";
1291           case 2:  return "Kilobytes";
1292           default: return "UNKNOWN-SA-VALUE";
1293         }
1294       case 12:
1295         return "Duration-Value";
1296       case 13:
1297         return "PRF-Value";
1298       case 14:
1299         return "Key-Length";
1300       case 15:
1301         return "Field-Size";
1302       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1303     }
1304   }
1305 }
1306
1307 static const char *
1308 attrtype2str(guint8 type) {
1309   switch (type) {
1310   case 0: return "Reserved";
1311   case 1: return "ISAKMP_CFG_REQUEST";
1312   case 2: return "ISAKMP_CFG_REPLY";
1313   case 3: return "ISAKMP_CFG_SET";
1314   case 4: return "ISAKMP_CFG_ACK";
1315   }
1316   if(type < 127)
1317     return "Future use";
1318   return "Private use";
1319 }
1320
1321 static const char *
1322 cfgattrident2str(guint16 ident) {
1323 #define NUM_ATTR_DEFINED        12
1324   static const char *msgs[NUM_PREDEFINED] = {
1325     "RESERVED",
1326     "INTERNAL_IP4_ADDRESS",
1327     "INTERNAL_IP4_NETMASK",
1328     "INTERNAL_IP4_DNS",
1329     "INTERNAL_IP4_NBNS",
1330     "INTERNAL_ADDRESS_EXPIREY",
1331     "INTERNAL_IP4_DHCP",
1332     "APPLICATION_VERSION"
1333     "INTERNAL_IP6_ADDRESS",
1334     "INTERNAL_IP6_NETMASK",
1335     "INTERNAL_IP6_DNS",
1336     "INTERNAL_IP6_NBNS",
1337     "INTERNAL_IP6_DHCP",
1338   };
1339   if(ident < NUM_ATTR_DEFINED)
1340     return msgs[ident];
1341   if(ident < 16383)
1342     return "Future use";
1343   switch(ident) {
1344   case 16520: return "XAUTH_TYPE";
1345   case 16521: return "XAUTH_USER_NAME";
1346   case 16522: return "XAUTH_USER_PASSWORD";
1347   case 16523: return "XAUTH_PASSCODE";
1348   case 16524: return "XAUTH_MESSAGE";
1349   case 16525: return "XAUTH_CHALLANGE";
1350   case 16526: return "XAUTH_DOMAIN";
1351   case 16527: return "XAUTH_STATUS";
1352   case 16528: return "XAUTH_NEXT_PIN";
1353   case 16529: return "XAUTH_ANSWER";
1354   default: return "Private use";
1355   }
1356 }
1357
1358 static const char *
1359 certtype2str(guint8 type) {
1360 #define NUM_CERTTYPE 11
1361   static const char *msgs[NUM_CERTTYPE] = {
1362     "NONE",
1363     "PKCS #7 wrapped X.509 certificate",
1364     "PGP Certificate",
1365     "DNS Signed Key",
1366     "X.509 Certificate - Signature",
1367     "X.509 Certificate - Key Exchange",
1368     "Kerberos Tokens",
1369     "Certificate Revocation List (CRL)",
1370     "Authority Revocation List (ARL)",
1371     "SPKI Certificate",
1372     "X.509 Certificate - Attribute",
1373   };
1374   if(type > NUM_CERTTYPE)
1375     return "RESERVED";
1376   return msgs[type];
1377 }
1378
1379 static gboolean
1380 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1381
1382   switch (len) {
1383   case 1:
1384     *num_p = tvb_get_guint8(tvb, offset);
1385     break;
1386   case 2:
1387     *num_p = tvb_get_ntohs(tvb, offset);
1388     break;
1389   case 3:
1390     *num_p = tvb_get_ntoh24(tvb, offset);
1391     break;
1392   case 4:
1393     *num_p = tvb_get_ntohl(tvb, offset);
1394     break;
1395   default:
1396     return FALSE;
1397   }
1398
1399   return TRUE;
1400 }
1401
1402 void
1403 proto_register_isakmp(void)
1404 {
1405 /*  static hf_register_info hf[] = {
1406     { &variable,
1407     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1408   };*/
1409   static gint *ett[] = {
1410     &ett_isakmp,
1411     &ett_isakmp_flags,
1412     &ett_isakmp_payload,
1413   };
1414
1415   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1416                                                "ISAKMP", "isakmp");
1417 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1418   proto_register_subtree_array(ett, array_length(ett));
1419 }
1420
1421 void
1422 proto_reg_handoff_isakmp(void)
1423 {
1424   dissector_handle_t isakmp_handle;
1425
1426   /*
1427    * Get handle for the AH & ESP dissectors.
1428    */
1429   esp_handle = find_dissector("esp");
1430   ah_handle = find_dissector("ah");
1431
1432   isakmp_handle = create_dissector_handle(dissect_isakmp, proto_isakmp);
1433   dissector_add("udp.port", UDP_PORT_ISAKMP, isakmp_handle);
1434   dissector_add("tcp.port", TCP_PORT_ISAKMP, isakmp_handle);
1435 }