Removed trailing whitespaces from .h and .c files using the
[obnox/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.59 2002/08/28 21:00:18 jmayer 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          15
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 };
280
281 #define VID_LEN 16
282 #define VID_MS_LEN 20
283 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 */
284
285 #define VID_CP_LEN 20
286 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};
287
288 static const guint8 VID_CYBERGUARD[VID_LEN] = {0x9A, 0xA1, 0xF3, 0xB4, 0x34, 0x72, 0xA4, 0x5D, 0x5F, 0x50, 0x6A, 0xEB, 0x26, 0xC, 0xF2, 0x14};
289
290 static const guint8 VID_SAFENET[VID_LEN] = {0x44, 0x85, 0x15, 0x2D, 0x18, 0xB6, 0xBB, 0xCD, 0x0B, 0xE8, 0xA8, 0x46, 0x95, 0x79, 0xDD, 0xCC};
291
292 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 */
293
294
295 static dissector_handle_t esp_handle;
296 static dissector_handle_t ah_handle;
297
298 static void
299 dissect_payloads(tvbuff_t *tvb, proto_tree *tree, guint8 initial_payload,
300                  int offset, int length)
301 {
302   guint8 payload, next_payload;
303   guint16               payload_length;
304   proto_tree *          ntree;
305
306   for (payload = initial_payload; length != 0; payload = next_payload) {
307     if (payload == LOAD_TYPE_NONE) {
308       /*
309        * What?  There's more stuff in this chunk of data, but the
310        * previous payload had a "next payload" type of None?
311        */
312       proto_tree_add_text(tree, tvb, offset, length,
313                           "Extra data: %s",
314                           tvb_bytes_to_str(tvb, offset, length));
315       break;
316     }
317     ntree = dissect_payload_header(tvb, offset, length, payload,
318       &next_payload, &payload_length, tree);
319     if (ntree == NULL)
320       break;
321     if (payload_length >= 4) {  /* XXX = > 4? */
322       if (payload < NUM_LOAD_TYPES) {
323         (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
324                                   -1);
325       }
326       else {
327         proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
328             "Payload");
329       }
330     }
331     else {
332         proto_tree_add_text(ntree, tvb, offset + 4, 0,
333             "Payload (bogus, length is %u, must be at least 4)",
334             payload_length);
335         payload_length = 4;
336     }
337     offset += payload_length;
338     length -= payload_length;
339   }
340 }
341
342 static void
343 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
344 {
345   int                   offset = 0;
346   struct isakmp_hdr     hdr;
347   proto_item *          ti;
348   proto_tree *          isakmp_tree = NULL;
349   struct udp_encap_hdr  encap_hdr;
350   guint32               len;
351   static const guint8   non_esp_marker[4] = { 0, 0, 0, 0 };
352   tvbuff_t *            next_tvb;
353
354   if (check_col(pinfo->cinfo, COL_PROTOCOL))
355     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISAKMP");
356   if (check_col(pinfo->cinfo, COL_INFO))
357     col_clear(pinfo->cinfo, COL_INFO);
358
359   hdr.length = tvb_get_ntohl(tvb, offset + sizeof(hdr) - sizeof(hdr.length));
360
361   if (tree) {
362     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, hdr.length, FALSE);
363     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
364   }
365
366   tvb_memcpy(tvb, (guint8 *)&encap_hdr, 0, sizeof(encap_hdr));
367
368   if (encap_hdr.non_esp_marker[0] == 0xFF) {
369     if (check_col(pinfo->cinfo, COL_INFO))
370       col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - NAT Keepalive");
371     return;
372   }
373   if (memcmp(encap_hdr.non_esp_marker,non_esp_marker,4) == 0) {
374     if (check_col(pinfo->cinfo, COL_INFO))
375           col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - ESP");
376     if (tree)
377       proto_tree_add_text(isakmp_tree, tvb, offset,
378                           sizeof(encap_hdr.non_esp_marker),
379                           "Non-ESP-Marker");
380     offset += sizeof(encap_hdr.non_esp_marker);
381     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
382     call_dissector(esp_handle, next_tvb, pinfo, tree);
383     return;
384   }
385   hdr.exch_type = tvb_get_guint8(tvb, sizeof(hdr.icookie) + sizeof(hdr.rcookie) + sizeof(hdr.next_payload) + sizeof(hdr.version));
386   if (check_col(pinfo->cinfo, COL_INFO))
387     col_add_str(pinfo->cinfo, COL_INFO, exchtype2str(hdr.exch_type));
388
389   if (tree) {
390     tvb_memcpy(tvb, (guint8 *)&hdr.icookie, offset, sizeof(hdr.icookie));
391     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.icookie),
392                         "Initiator cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.icookie)));
393     offset += sizeof(hdr.icookie);
394
395     tvb_memcpy(tvb, (guint8 *)&hdr.rcookie, offset, sizeof(hdr.rcookie));
396     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.rcookie),
397                         "Responder cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.rcookie)));
398     offset += sizeof(hdr.rcookie);
399
400     hdr.next_payload = tvb_get_guint8(tvb, offset);
401     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.next_payload),
402                         "Next payload: %s (%u)",
403                         payloadtype2str(hdr.next_payload), hdr.next_payload);
404     offset += sizeof(hdr.next_payload);
405
406     hdr.version = tvb_get_guint8(tvb, offset);
407     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.version),
408                         "Version: %u.%u",
409                         hi_nibble(hdr.version), lo_nibble(hdr.version));
410     offset += sizeof(hdr.version);
411
412     hdr.exch_type = tvb_get_guint8(tvb, offset);
413     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.exch_type),
414                         "Exchange type: %s (%u)",
415                         exchtype2str(hdr.exch_type), hdr.exch_type);
416     offset += sizeof(hdr.exch_type);
417
418     {
419       proto_item *      fti;
420       proto_tree *      ftree;
421
422       hdr.flags = tvb_get_guint8(tvb, offset);
423       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.flags), "Flags");
424       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
425
426       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
427                           decode_boolean_bitfield(hdr.flags, E_FLAG, sizeof(hdr.flags)*8,
428                                                   "Encryption", "No encryption"));
429       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
430                           decode_boolean_bitfield(hdr.flags, C_FLAG, sizeof(hdr.flags)*8,
431                                                   "Commit", "No commit"));
432       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
433                           decode_boolean_bitfield(hdr.flags, A_FLAG, sizeof(hdr.flags)*8,
434                                                   "Authentication", "No authentication"));
435       offset += sizeof(hdr.flags);
436     }
437
438     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.message_id),
439         "Message ID: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.message_id)));
440     offset += sizeof(hdr.message_id);
441
442     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.length),
443                         "Length: %u", hdr.length);
444     offset += sizeof(hdr.length);
445
446     len = hdr.length - sizeof(hdr);
447
448     if (hdr.flags & E_FLAG) {
449       if (len && isakmp_tree) {
450         proto_tree_add_text(isakmp_tree, tvb, offset, len,
451                         "Encrypted payload (%d byte%s)",
452                         len, plurality(len, "", "s"));
453       }
454     } else
455       dissect_payloads(tvb, isakmp_tree, hdr.next_payload, offset, len);
456   }
457 }
458
459 static proto_tree *
460 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
461     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
462 {
463   guint8                next_payload;
464   guint16               payload_length;
465   proto_item *          ti;
466   proto_tree *          ntree;
467
468   if (length < 4) {
469     proto_tree_add_text(tree, tvb, offset, length,
470           "Not enough room in payload for all transforms");
471     return NULL;
472   }
473   next_payload = tvb_get_guint8(tvb, offset);
474   payload_length = tvb_get_ntohs(tvb, offset + 2);
475
476   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
477             "%s payload", loadtype2str(payload));
478   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
479
480   proto_tree_add_text(ntree, tvb, offset, 1,
481                       "Next payload: %s (%u)",
482                       payloadtype2str(next_payload), next_payload);
483   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
484
485   *next_payload_p = next_payload;
486   *payload_length_p = payload_length;
487   return ntree;
488 }
489
490 static void
491 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
492     int unused _U_)
493 {
494   guint32               doi;
495   guint32               situation;
496
497   if (length < 4) {
498     proto_tree_add_text(tree, tvb, offset, length,
499                         "DOI %s (length is %u, should be >= 4)",
500                         tvb_bytes_to_str(tvb, offset, length), length);
501     return;
502   }
503   doi = tvb_get_ntohl(tvb, offset);
504   proto_tree_add_text(tree, tvb, offset, 4,
505                       "Domain of interpretation: %s (%u)",
506                       doitype2str(doi), doi);
507   offset += 4;
508   length -= 4;
509
510   if (doi == 1) {
511     /* IPSEC */
512     if (length < 4) {
513       proto_tree_add_text(tree, tvb, offset, length,
514                           "Situation: %s (length is %u, should be >= 4)",
515                           tvb_bytes_to_str(tvb, offset, length), length);
516       return;
517     }
518     situation = tvb_get_ntohl(tvb, offset);
519     proto_tree_add_text(tree, tvb, offset, 4,
520                         "Situation: %s (%u)",
521                         situation2str(situation), situation);
522     offset += 4;
523     length -= 4;
524
525     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length);
526   } else {
527     /* Unknown */
528     proto_tree_add_text(tree, tvb, offset, length,
529                         "Situation: %s",
530                         tvb_bytes_to_str(tvb, offset, length));
531   }
532 }
533
534 static void
535 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
536     int unused _U_)
537 {
538   guint8                protocol_id;
539   guint8                spi_size;
540   guint8                num_transforms;
541   guint8                next_payload;
542   guint16               payload_length;
543   proto_tree *          ntree;
544   guint8                proposal_num;
545
546   proposal_num = tvb_get_guint8(tvb, offset);
547
548   proto_item_append_text(tree, " # %d",proposal_num);
549   proto_tree_add_text(tree, tvb, offset, 1,
550                       "Proposal number: %u", proposal_num);
551   offset += 1;
552   length -= 1;
553
554   protocol_id = tvb_get_guint8(tvb, offset);
555   proto_tree_add_text(tree, tvb, offset, 1,
556                       "Protocol ID: %s (%u)",
557                       proto2str(protocol_id), protocol_id);
558   offset += 1;
559   length -= 1;
560
561   spi_size = tvb_get_guint8(tvb, offset);
562   proto_tree_add_text(tree, tvb, offset, 1,
563                       "SPI size: %u", spi_size);
564   offset += 1;
565   length -= 1;
566
567   num_transforms = tvb_get_guint8(tvb, offset);
568   proto_tree_add_text(tree, tvb, offset, 1,
569                       "Number of transforms: %u", num_transforms);
570   offset += 1;
571   length -= 1;
572
573   if (spi_size) {
574     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI: %s",
575                         tvb_bytes_to_str(tvb, offset, spi_size));
576     offset += spi_size;
577     length -= spi_size;
578   }
579
580   while (num_transforms > 0) {
581     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
582       &next_payload, &payload_length, tree);
583     if (ntree == NULL)
584       break;
585     if (length < payload_length) {
586       proto_tree_add_text(tree, tvb, offset + 4, length,
587           "Not enough room in payload for all transforms");
588       break;
589     }
590     if (payload_length >= 4)
591       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
592     else
593       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
594     offset += payload_length;
595     length -= payload_length;
596     num_transforms--;
597   }
598 }
599
600 static void
601 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
602     int protocol_id)
603 {
604   guint8                transform_id;
605   guint8                transform_num;
606
607   transform_num = tvb_get_guint8(tvb, offset);
608   proto_item_append_text(tree," # %d",transform_num);
609   proto_tree_add_text(tree, tvb, offset, 1,
610                       "Transform number: %u", transform_num);
611   offset += 1;
612   length -= 1;
613
614   transform_id = tvb_get_guint8(tvb, offset);
615   switch (protocol_id) {
616   default:
617     proto_tree_add_text(tree, tvb, offset, 1,
618                         "Transform ID: %u", transform_id);
619     break;
620   case 1:       /* ISAKMP */
621     proto_tree_add_text(tree, tvb, offset, 1,
622                         "Transform ID: %s (%u)",
623                         trans2str(transform_id), transform_id);
624     break;
625   case 2:       /* AH */
626     proto_tree_add_text(tree, tvb, offset, 1,
627                         "Transform ID: %s (%u)",
628                         ah_trans2str(transform_id), transform_id);
629     break;
630   case 3:       /* ESP */
631     proto_tree_add_text(tree, tvb, offset, 1,
632                         "Transform ID: %s (%u)",
633                         esp_trans2str(transform_id), transform_id);
634     break;
635   case 4:       /* IPCOMP */
636     proto_tree_add_text(tree, tvb, offset, 1,
637                         "Transform ID: %s (%u)",
638                         ipcomp_trans2str(transform_id), transform_id);
639     break;
640   }
641   offset += 3;
642   length -= 3;
643
644   while (length>0) {
645     const char *str;
646     int ike_phase1 = 0;
647     guint16 aft     = tvb_get_ntohs(tvb, offset);
648     guint16 type    = aft & 0x7fff;
649     guint16 len;
650     guint32 val;
651     guint pack_len;
652
653     if (protocol_id == 1 && transform_id == 1) {
654       ike_phase1 = 1;
655       str = p1_atttype2str(type);
656     }
657     else {
658       str = atttype2str(type);
659     }
660
661     if (aft & 0x8000) {
662       val = tvb_get_ntohs(tvb, offset + 2);
663       proto_tree_add_text(tree, tvb, offset, 4,
664                           "%s (%u): %s (%u)",
665                           str, type,
666                           value2str(ike_phase1, type, val), val);
667       offset += 4;
668       length -= 4;
669     }
670     else {
671       len = tvb_get_ntohs(tvb, offset + 2);
672       pack_len = 4 + len;
673       if (!get_num(tvb, offset + 4, len, &val)) {
674         proto_tree_add_text(tree, tvb, offset, pack_len,
675                             "%s (%u): <too big (%u bytes)>",
676                             str, type, len);
677       } else {
678         proto_tree_add_text(tree, tvb, offset, pack_len,
679                             "%s (%u): %s (%u)",
680                             str, type,
681                             value2str(ike_phase1, type, val), val);
682       }
683       offset += pack_len;
684       length -= pack_len;
685     }
686   }
687 }
688
689 static void
690 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
691     int unused _U_)
692 {
693   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
694 }
695
696 static void
697 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
698     int unused _U_)
699 {
700   guint8                id_type;
701   guint8                protocol_id;
702   guint16               port;
703
704   id_type = tvb_get_guint8(tvb, offset);
705   proto_tree_add_text(tree, tvb, offset, 1,
706                       "ID type: %s (%u)", id2str(id_type), id_type);
707   offset += 1;
708   length -= 1;
709
710   protocol_id = tvb_get_guint8(tvb, offset);
711   if (protocol_id == 0) {
712     proto_tree_add_text(tree, tvb, offset, 1,
713                         "Protocol ID: Unused");
714   } else {
715     proto_tree_add_text(tree, tvb, offset, 1,
716                         "Protocol ID: %s (%u)",
717                         ipprotostr(protocol_id), protocol_id);
718   }
719   offset += 1;
720   length -= 1;
721
722   port = tvb_get_ntohs(tvb, offset);
723   if (port == 0)
724     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
725   else
726     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
727   offset += 2;
728   length -= 2;
729
730   switch (id_type) {
731     case 1:
732       proto_tree_add_text(tree, tvb, offset, length,
733                           "Identification data: %s",
734                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
735       break;
736     case 2:
737     case 3:
738       proto_tree_add_text(tree, tvb, offset, length,
739                           "Identification data: %.*s", length,
740                           tvb_get_ptr(tvb, offset, length));
741       break;
742     case 4:
743       proto_tree_add_text(tree, tvb, offset, length,
744                           "Identification data: %s/%s",
745                           ip_to_str(tvb_get_ptr(tvb, offset, 4)),
746                           ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
747       break;
748     default:
749       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
750       break;
751   }
752 }
753
754 static void
755 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
756     int unused _U_)
757 {
758   guint8                cert_enc;
759
760   cert_enc = tvb_get_guint8(tvb, offset);
761   proto_tree_add_text(tree, tvb, offset, 1,
762                       "Certificate encoding: %u - %s",
763                       cert_enc, certtype2str(cert_enc));
764   offset += 1;
765   length -= 1;
766
767   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
768 }
769
770 static void
771 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
772     int unused _U_)
773 {
774   guint8                cert_type;
775
776   cert_type = tvb_get_guint8(tvb, offset);
777   proto_tree_add_text(tree, tvb, offset, 1,
778                       "Certificate type: %u - %s",
779                       cert_type, certtype2str(cert_type));
780   offset += 1;
781   length -= 1;
782
783   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
784 }
785
786 static void
787 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
788     int unused _U_)
789 {
790   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
791 }
792
793 static void
794 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
795     int unused _U_)
796 {
797   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
798 }
799
800 static void
801 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
802     int unused _U_)
803 {
804   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
805 }
806
807 static void
808 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
809     int unused _U_)
810 {
811   guint32               doi;
812   guint8                protocol_id;
813   guint8                spi_size;
814   guint16               msgtype;
815
816   doi = tvb_get_ntohl(tvb, offset);
817   proto_tree_add_text(tree, tvb, offset, 4,
818                       "Domain of Interpretation: %s (%u)",
819                       doitype2str(doi), doi);
820   offset += 4;
821   length -= 4;
822
823   protocol_id = tvb_get_guint8(tvb, offset);
824   proto_tree_add_text(tree, tvb, offset, 1,
825                       "Protocol ID: %s (%u)",
826                       proto2str(protocol_id), protocol_id);
827   offset += 1;
828   length -= 1;
829
830   spi_size = tvb_get_guint8(tvb, offset);
831   proto_tree_add_text(tree, tvb, offset, 1,
832                       "SPI size: %u", spi_size);
833   offset += 1;
834   length -= 1;
835
836   msgtype = tvb_get_ntohs(tvb, offset);
837   proto_tree_add_text(tree, tvb, offset, 2,
838                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
839   offset += 2;
840   length -= 2;
841
842   if (spi_size) {
843     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
844     offset += spi_size;
845     length -= spi_size;
846   }
847
848   if (length > 0)
849     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
850 }
851
852 static void
853 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
854     int unused _U_)
855 {
856   guint32               doi;
857   guint8                protocol_id;
858   guint8                spi_size;
859   guint16               num_spis;
860   guint16               i;
861
862   doi = tvb_get_ntohl(tvb, offset);
863   proto_tree_add_text(tree, tvb, offset, 4,
864                       "Domain of Interpretation: %s (%u)",
865                       doitype2str(doi), doi);
866   offset += 4;
867   length -= 4;
868
869   protocol_id = tvb_get_guint8(tvb, offset);
870   proto_tree_add_text(tree, tvb, offset, 1,
871                       "Protocol ID: %s (%u)",
872                       proto2str(protocol_id), protocol_id);
873   offset += 1;
874   length -= 1;
875
876   spi_size = tvb_get_guint8(tvb, offset);
877   proto_tree_add_text(tree, tvb, offset, 1,
878                       "SPI size: %u", spi_size);
879   offset += 1;
880   length -= 1;
881
882   num_spis = tvb_get_ntohs(tvb, offset);
883   proto_tree_add_text(tree, tvb, offset, 2,
884                       "Number of SPIs: %u", num_spis);
885   offset += 2;
886   length -= 2;
887
888   for (i = 0; i < num_spis; ++i) {
889     if (length < spi_size) {
890       proto_tree_add_text(tree, tvb, offset, length,
891           "Not enough room in payload for all SPI's");
892       break;
893     }
894     proto_tree_add_text(tree, tvb, offset, spi_size,
895                         "SPI (%d)", i);
896     offset += spi_size;
897     length -= spi_size;
898   }
899 }
900
901 static void
902 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
903     int unused _U_)
904 {
905   guint32 CPproduct, CPversion;
906   const guint8 * pVID;
907   proto_item * pt;
908   proto_tree * ntree;
909   pVID = tvb_get_ptr(tvb, offset, length);
910   pt = proto_tree_add_text(tree, tvb, offset, length, "Vendor ID: ");
911   if (memcmp(pVID, VID_MS_W2K_WXP, isakmp_min(VID_MS_LEN, length)) == 0)
912         proto_item_append_text(pt, "Microsoft Win2K/WinXP");
913   else
914   if (memcmp(pVID, VID_CP, isakmp_min(VID_CP_LEN, length)) == 0)
915   {
916         proto_item_append_text(pt, "Check Point");
917         offset += VID_CP_LEN;
918         CPproduct = tvb_get_ntohl(tvb, offset);
919         ntree = proto_item_add_subtree(pt, ett_isakmp_payload);
920         pt = proto_tree_add_text(ntree, tvb, offset, sizeof(CPproduct), "Check Point Product: ");
921         switch (CPproduct) {
922                 case 1: proto_item_append_text(pt, "VPN-1");
923                         break;
924                 case 2: proto_item_append_text(pt, "SecuRemote/SecureClient");
925                         break;
926                 default: proto_item_append_text(pt, "Unknown CP product!");
927                         break;
928         }
929         offset += sizeof(CPproduct);
930         CPversion = tvb_get_ntohl(tvb, offset);
931         pt = proto_tree_add_text(ntree, tvb, offset, length, "Version: ");
932         switch (CPversion) {
933                 case 2: proto_item_append_text(pt, "4.1");
934                         break;
935                 case 3: proto_item_append_text(pt, "4.1 SP-1");
936                         break;
937                 case 4002: proto_item_append_text(pt, "4.1 (SP-2 or above)");
938                         break;
939                 case 5000: proto_item_append_text(pt, "NG");
940                         break;
941                 case 5001: proto_item_append_text(pt, "NG Feature Pack 1");
942                         break;
943                 case 5002: proto_item_append_text(pt, "NG Feature Pack 2");
944                         break;
945                 case 5003: proto_item_append_text(pt, "NG Feature Pack 3");
946                         break;
947                 default: proto_item_append_text(pt, " Uknown CP version!");
948                         break;
949         }
950   }
951   else
952   if (memcmp(pVID, VID_CYBERGUARD, isakmp_min(VID_LEN, length)) == 0)
953         proto_item_append_text(pt, "Cyber Guard");
954   else
955   if (memcmp(pVID, VID_SAFENET, isakmp_min(VID_LEN, length)) == 0)
956         proto_item_append_text(pt, "SafeNet");
957   else
958   if (memcmp(pVID,  VID_draft_ietf_ipsec_nat_t_ike_03, isakmp_min(VID_LEN, length)) == 0)
959         proto_item_append_text(pt, "draft-ietf-ipsec-nat-t-ike-03");
960   else
961         proto_item_append_text(pt, "unknown vendor ID: 0x%s",tvb_bytes_to_str(tvb, offset, length));
962 }
963
964 static void
965 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
966     int unused _U_)
967 {
968   guint8                type;
969
970   type = tvb_get_guint8(tvb, offset);
971   proto_tree_add_text(tree, tvb, offset, 1,
972                       "Type %s (%u)",attrtype2str(type),type);
973
974   offset += 2;
975   length -= 2;
976
977   proto_tree_add_text(tree, tvb, offset, 2,
978                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
979   offset += 2;
980   length -= 2;
981
982   while(length>0) {
983     guint16 aft     = tvb_get_ntohs(tvb, offset);
984     guint16 type    = aft & 0x7fff;
985     guint16 len;
986     guint32 val;
987     guint pack_len;
988
989     if (aft & 0x8000) {
990       val = tvb_get_ntohs(tvb, offset + 2);
991       proto_tree_add_text(tree, tvb, offset, 4,
992                           "%s (%u)", cfgattrident2str(type), val);
993       offset += 4;
994       length -= 4;
995     }
996     else {
997       len = tvb_get_ntohs(tvb, offset + 2);
998       pack_len = 4 + len;
999       if (!get_num(tvb, offset + 4, len, &val)) {
1000         proto_tree_add_text(tree, tvb, offset, pack_len,
1001                             "%s: <too big (%u bytes)>",
1002                             cfgattrident2str(type), len);
1003       } else {
1004         proto_tree_add_text(tree, tvb, offset, 4,
1005                             "%s (%ue)", cfgattrident2str(type),
1006                             val);
1007       }
1008       offset += pack_len;
1009       length -= pack_len;
1010     }
1011   }
1012 }
1013
1014 static const char *
1015 payloadtype2str(guint8 type) {
1016
1017   if (type < NUM_LOAD_TYPES) return strfuncs[type].str;
1018   if (type < 128)            return "RESERVED";
1019   if (type < 256)            return "Private USE";
1020
1021   return "Huh? You should never see this! Shame on you!";
1022 }
1023
1024 static const char *
1025 exchtype2str(guint8 type) {
1026
1027 #define NUM_EXCHSTRS    7
1028   static const char * exchstrs[NUM_EXCHSTRS] = {
1029     "NONE",
1030     "Base",
1031     "Identity Protection (Main Mode)",
1032     "Authentication Only",
1033     "Aggressive",
1034     "Informational",
1035     "Transaction (Config Mode)"
1036   };
1037
1038   if (type < NUM_EXCHSTRS) return exchstrs[type];
1039   if (type < 32)           return "ISAKMP Future Use";
1040   switch (type) {
1041   case 32:
1042     return "Quick Mode";
1043   case 33:
1044     return "New Group Mode";
1045   }
1046   if (type < 240)          return "DOI Specific Use";
1047   if (type < 256)          return "Private Use";
1048
1049   return "Huh? You should never see this! Shame on you!";
1050 }
1051
1052 static const char *
1053 doitype2str(guint32 type) {
1054   if (type == 1) return "IPSEC";
1055   return "Unknown DOI Type";
1056 }
1057
1058 static const char *
1059 msgtype2str(guint16 type) {
1060
1061 #define NUM_PREDEFINED  31
1062   static const char *msgs[NUM_PREDEFINED] = {
1063     "<UNKNOWN>",
1064     "INVALID-PAYLOAD-TYPE",
1065     "DOI-NOT-SUPPORTED",
1066     "SITUATION-NOT-SUPPORTED",
1067     "INVALID-COOKIE",
1068     "INVALID-MAJOR-VERSION",
1069     "INVALID-MINOR-VERSION",
1070     "INVALID-EXCHANGE-TYPE",
1071     "INVALID-FLAGS",
1072     "INVALID-MESSAGE-ID",
1073     "INVALID-PROTOCOL-ID",
1074     "INVALID-SPI",
1075     "INVALID-TRANSFORM-ID",
1076     "ATTRIBUTES-NOT-SUPPORTED",
1077     "NO-PROPOSAL-CHOSEN",
1078     "BAD-PROPOSAL-SYNTAX",
1079     "PAYLOAD-MALFORMED",
1080     "INVALID-KEY-INFORMATION",
1081     "INVALID-ID-INFORMATION",
1082     "INVALID-CERT-ENCODING",
1083     "INVALID-CERTIFICATE",
1084     "CERT-TYPE-UNSUPPORTED",
1085     "INVALID-CERT-AUTHORITY",
1086     "INVALID-HASH-INFORMATION",
1087     "AUTHENTICATION-FAILED",
1088     "INVALID-SIGNATURE",
1089     "ADDRESS-NOTIFICATION",
1090     "NOTIFY-SA-LIFETIME",
1091     "CERTIFICATE-UNAVAILABLE",
1092     "UNSUPPORTED-EXCHANGE-TYPE",
1093     "UNEQUAL-PAYLOAD-LENGTHS"
1094   };
1095
1096   if (type < NUM_PREDEFINED) return msgs[type];
1097   if (type < 8192)           return "RESERVED (Future Use)";
1098   if (type < 16384)          return "Private Use";
1099   if (type < 16385)          return "CONNECTED";
1100   if (type < 24576)          return "RESERVED (Future Use) - status";
1101   if (type < 24577)          return "RESPONDER-LIFETIME";
1102   if (type < 24578)          return "REPLAY-STATUS";
1103   if (type < 24579)          return "INITIAL-CONTACT";
1104   if (type < 32768)          return "DOI-specific codes";
1105   if (type < 40960)          return "Private Use - status";
1106   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
1107
1108   return "Huh? You should never see this! Shame on you!";
1109 }
1110
1111 static const char *
1112 situation2str(guint32 type) {
1113
1114 #define SIT_MSG_NUM     1024
1115 #define SIT_IDENTITY    0x01
1116 #define SIT_SECRECY     0x02
1117 #define SIT_INTEGRITY   0x04
1118
1119   static char   msg[SIT_MSG_NUM];
1120   int           n = 0;
1121   char *        sep = "";
1122   int           ret;
1123
1124   if (type & SIT_IDENTITY) {
1125     ret = snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
1126     if (ret == -1) {
1127       /* Some versions of snprintf return -1 if they'd truncate the output. */
1128       return msg;
1129     }
1130     n += ret;
1131     sep = " & ";
1132   }
1133   if (type & SIT_SECRECY) {
1134     if (n >= SIT_MSG_NUM) {
1135       /* No more room. */
1136       return msg;
1137     }
1138     ret = snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
1139     if (ret == -1) {
1140       /* Some versions of snprintf return -1 if they'd truncate the output. */
1141       return msg;
1142     }
1143     n += ret;
1144     sep = " & ";
1145   }
1146   if (type & SIT_INTEGRITY) {
1147     if (n >= SIT_MSG_NUM) {
1148       /* No more room. */
1149       return msg;
1150     }
1151     ret = snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
1152     if (ret == -1) {
1153       /* Some versions of snprintf return -1 if they'd truncate the output. */
1154       return msg;
1155     }
1156     n += ret;
1157     sep = " & ";
1158   }
1159
1160   return msg;
1161 }
1162
1163 static const char *
1164 value2str(int ike_p1, guint16 att_type, guint16 value) {
1165
1166   if (value == 0) return "RESERVED";
1167
1168   if (!ike_p1) {
1169   switch (att_type) {
1170     case 1:
1171       switch (value) {
1172         case 0: return "RESERVED";
1173         case 1:  return "Seconds";
1174         case 2:  return "Kilobytes";
1175         default: return "UNKNOWN-SA-VALUE";
1176       }
1177     case 2:
1178       return "Duration-Value";
1179     case 3:
1180       return "Group-Value";
1181     case 4:
1182       switch (value) {
1183         case 0:  return "RESERVED";
1184         case 1:  return "Tunnel";
1185         case 2:  return "Transport";
1186         case 61440: return "Check Point IPSec UDP Encapsulation";
1187         case 61443: return "UDP-Encapsulated-Tunnel (draft)";
1188         case 61444: return "UDP-Encapsulated-Transport (draft)";
1189         default: return "UNKNOWN-ENCAPSULATION-VALUE";
1190       }
1191     case 5:
1192       switch (value) {
1193         case 0:  return "RESERVED";
1194         case 1:  return "HMAC-MD5";
1195         case 2:  return "HMAC-SHA";
1196         case 3:  return "DES-MAC";
1197         case 4:  return "KPDK";
1198         case 5:  return "HMAC-SHA2-256";
1199         case 6:  return "HMAC-SHA2-384";
1200         case 7:  return "HMAC-SHA2-512";
1201         default: return "UNKNOWN-AUTHENTICATION-VALUE";
1202       }
1203     case 6:
1204       return "Key-Length";
1205     case 7:
1206       return "Key-Rounds";
1207     case 8:
1208       return "Compress-Dictionary-size";
1209     case 9:
1210       return "Compress Private Algorithm";
1211     default: return "UNKNOWN-ATTRIBUTE-TYPE";
1212   }
1213   }
1214   else {
1215     switch (att_type) {
1216       case 1:
1217         switch (value) {
1218           case 1:  return "DES-CBC";
1219           case 2:  return "IDEA-CBC";
1220           case 3:  return "BLOWFISH-CBC";
1221           case 4:  return "RC5-R16-B64-CBC";
1222           case 5:  return "3DES-CBC";
1223           case 6:  return "CAST-CBC";
1224           case 7:  return "AES-CBC";
1225           default: return "UNKNOWN-ENCRYPTION-ALG";
1226         }
1227       case 2:
1228         switch (value) {
1229           case 1:  return "MD5";
1230           case 2:  return "SHA";
1231           case 3:  return "TIGER";
1232           case 4:  return "SHA2-256";
1233           case 5:  return "SHA2-384";
1234           case 6:  return "SHA2-512";
1235           default: return "UNKNOWN-HASH-ALG";
1236         }
1237       case 3:
1238         switch (value) {
1239           case 1:  return "PSK";
1240           case 2:  return "DSS-SIG";
1241           case 3:  return "RSA-SIG";
1242           case 4:  return "RSA-ENC";
1243           case 5:  return "RSA-Revised-ENC";
1244           case 6:  return "Encryption with El-Gamal";
1245           case 7:  return "Revised encryption with El-Gamal";
1246           case 8:  return "ECDSA signatures";
1247           case 64221: return "HybridInitRSA";
1248           case 64222: return "HybridRespRSA";
1249           case 64223: return "HybridInitDSS";
1250           case 64224: return "HybridRespDSS";
1251           case 65001: return "XAUTHInitPreShared";
1252           case 65002: return "XAUTHRespPreShared";
1253           case 65003: return "XAUTHInitDSS";
1254           case 65004: return "XAUTHRespDSS";
1255           case 65005: return "XAUTHInitRSA";
1256           case 65006: return "XAUTHRespRSA";
1257           case 65007: return "XAUTHInitRSAEncryption";
1258           case 65008: return "XAUTHRespRSAEncryption";
1259           case 65009: return "XAUTHInitRSARevisedEncryption";
1260           case 65010: return "XAUTHRespRSARevisedEncryption";
1261           default: return "UNKNOWN-AUTH-METHOD";
1262         }
1263       case 4: return grpdesc2str(value);
1264       case 6:
1265       case 7:
1266       case 8:
1267       case 9:
1268       case 10:
1269       case 16:
1270         return "Group-Value";
1271       case 5:
1272         switch (value) {
1273           case 1:  return "MODP";
1274           case 2:  return "ECP";
1275           case 3:  return "EC2N";
1276           default: return "UNKNOWN-GROUPT-TYPE";
1277         }
1278       case 11:
1279         switch (value) {
1280           case 1:  return "Seconds";
1281           case 2:  return "Kilobytes";
1282           default: return "UNKNOWN-SA-VALUE";
1283         }
1284       case 12:
1285         return "Duration-Value";
1286       case 13:
1287         return "PRF-Value";
1288       case 14:
1289         return "Key-Length";
1290       case 15:
1291         return "Field-Size";
1292       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1293     }
1294   }
1295 }
1296
1297 static const char *
1298 attrtype2str(guint8 type) {
1299   switch (type) {
1300   case 0: return "Reserved";
1301   case 1: return "ISAKMP_CFG_REQUEST";
1302   case 2: return "ISAKMP_CFG_REPLY";
1303   case 3: return "ISAKMP_CFG_SET";
1304   case 4: return "ISAKMP_CFG_ACK";
1305   }
1306   if(type < 127)
1307     return "Future use";
1308   return "Private use";
1309 }
1310
1311 static const char *
1312 cfgattrident2str(guint16 ident) {
1313 #define NUM_ATTR_DEFINED        12
1314   static const char *msgs[NUM_PREDEFINED] = {
1315     "RESERVED",
1316     "INTERNAL_IP4_ADDRESS",
1317     "INTERNAL_IP4_NETMASK",
1318     "INTERNAL_IP4_DNS",
1319     "INTERNAL_IP4_NBNS",
1320     "INTERNAL_ADDRESS_EXPIREY",
1321     "INTERNAL_IP4_DHCP",
1322     "APPLICATION_VERSION"
1323     "INTERNAL_IP6_ADDRESS",
1324     "INTERNAL_IP6_NETMASK",
1325     "INTERNAL_IP6_DNS",
1326     "INTERNAL_IP6_NBNS",
1327     "INTERNAL_IP6_DHCP",
1328   };
1329   if(ident < NUM_ATTR_DEFINED)
1330     return msgs[ident];
1331   if(ident < 16383)
1332     return "Future use";
1333   switch(ident) {
1334   case 16520: return "XAUTH_TYPE";
1335   case 16521: return "XAUTH_USER_NAME";
1336   case 16522: return "XAUTH_USER_PASSWORD";
1337   case 16523: return "XAUTH_PASSCODE";
1338   case 16524: return "XAUTH_MESSAGE";
1339   case 16525: return "XAUTH_CHALLANGE";
1340   case 16526: return "XAUTH_DOMAIN";
1341   case 16527: return "XAUTH_STATUS";
1342   case 16528: return "XAUTH_NEXT_PIN";
1343   case 16529: return "XAUTH_ANSWER";
1344   default: return "Private use";
1345   }
1346 }
1347
1348 static const char *
1349 certtype2str(guint8 type) {
1350 #define NUM_CERTTYPE 11
1351   static const char *msgs[NUM_CERTTYPE] = {
1352     "NONE",
1353     "PKCS #7 wrapped X.509 certificate",
1354     "PGP Certificate",
1355     "DNS Signed Key",
1356     "X.509 Certificate - Signature",
1357     "X.509 Certificate - Key Exchange",
1358     "Kerberos Tokens",
1359     "Certificate Revocation List (CRL)",
1360     "Authority Revocation List (ARL)",
1361     "SPKI Certificate",
1362     "X.509 Certificate - Attribute",
1363   };
1364   if(type > NUM_CERTTYPE)
1365     return "RESERVED";
1366   return msgs[type];
1367 }
1368
1369 static gboolean
1370 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1371
1372   switch (len) {
1373   case 1:
1374     *num_p = tvb_get_guint8(tvb, offset);
1375     break;
1376   case 2:
1377     *num_p = tvb_get_ntohs(tvb, offset);
1378     break;
1379   case 3:
1380     *num_p = tvb_get_ntoh24(tvb, offset);
1381     break;
1382   case 4:
1383     *num_p = tvb_get_ntohl(tvb, offset);
1384     break;
1385   default:
1386     return FALSE;
1387   }
1388
1389   return TRUE;
1390 }
1391
1392 void
1393 proto_register_isakmp(void)
1394 {
1395 /*  static hf_register_info hf[] = {
1396     { &variable,
1397     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1398   };*/
1399   static gint *ett[] = {
1400     &ett_isakmp,
1401     &ett_isakmp_flags,
1402     &ett_isakmp_payload,
1403   };
1404
1405   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1406                                                "ISAKMP", "isakmp");
1407 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1408   proto_register_subtree_array(ett, array_length(ett));
1409 }
1410
1411 void
1412 proto_reg_handoff_isakmp(void)
1413 {
1414   dissector_handle_t isakmp_handle;
1415
1416   /*
1417    * Get handle for the AH & ESP dissectors.
1418    */
1419   esp_handle = find_dissector("esp");
1420   ah_handle = find_dissector("ah");
1421
1422   isakmp_handle = create_dissector_handle(dissect_isakmp, proto_isakmp);
1423   dissector_add("udp.port", UDP_PORT_ISAKMP, isakmp_handle);
1424   dissector_add("tcp.port", TCP_PORT_ISAKMP, isakmp_handle);
1425 }