Use system's version of AM_PATH_GLIB macro.
[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)
4  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
5  *
6  * $Id: packet-isakmp.c,v 1.38 2001/04/17 06:29:12 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
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 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <stdio.h>
37
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41
42 #include <glib.h>
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #include "packet.h"
49 #include "ipproto.h"
50
51 static int proto_isakmp = -1;
52
53 static gint ett_isakmp = -1;
54 static gint ett_isakmp_flags = -1;
55 static gint ett_isakmp_payload = -1;
56
57 #define UDP_PORT_ISAKMP 500
58
59 #define NUM_PROTO_TYPES 5
60 #define proto2str(t)    \
61   ((t < NUM_PROTO_TYPES) ? prototypestr[t] : "UNKNOWN-PROTO-TYPE")
62
63 static const char *prototypestr[NUM_PROTO_TYPES] = {
64   "RESERVED",
65   "ISAKMP",
66   "IPSEC_AH",
67   "IPSEC_ESP",
68   "IPCOMP"
69 };
70
71 #define NUM_P1_ATT_TYPES        17
72 #define p1_atttype2str(t)       \
73   ((t < NUM_P1_ATT_TYPES) ? p1_atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
74
75 static const char *p1_atttypestr[NUM_P1_ATT_TYPES] = {
76   "UNKNOWN-ATTRIBUTE-TYPE",
77   "Encryption-Algorithm",
78   "Hash-Algorithm",
79   "Authentication-Method",
80   "Group-Description",
81   "Group-Type",
82   "Group-Prime",
83   "Group-Generator-One",
84   "Group-Generator-Two",
85   "Group-Curve-A",
86   "Group-Curve-B",
87   "Life-Type",
88   "Life-Duration",
89   "PRF",
90   "Key-Length",
91   "Field-Size",
92   "Group-Order"
93 };
94
95 #define NUM_ATT_TYPES   11
96 #define atttype2str(t)  \
97   ((t < NUM_ATT_TYPES) ? atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
98
99 static const char *atttypestr[NUM_ATT_TYPES] = {
100   "UNKNOWN-ATTRIBUTE-TYPE",
101   "SA-Life-Type",
102   "SA-Life-Duration",
103   "Group-Description",
104   "Encapsulation-Mode",
105   "Authentication-Algorithm",
106   "Key-Length",
107   "Key-Rounds",
108   "Compress-Dictinary-Size",
109   "Compress-Private-Algorithm",
110   "ECN Tunnel"
111 };
112
113 #define NUM_TRANS_TYPES 2
114 #define trans2str(t)    \
115   ((t < NUM_TRANS_TYPES) ? transtypestr[t] : "UNKNOWN-TRANS-TYPE")
116
117 static const char *transtypestr[NUM_TRANS_TYPES] = {
118   "RESERVED",
119   "KEY_IKE"
120 };
121
122 #define NUM_AH_TRANS_TYPES      8
123 #define ah_trans2str(t)         \
124   ((t < NUM_AH_TRANS_TYPES) ? ah_transtypestr[t] : "UNKNOWN-AH-TRANS-TYPE")
125
126 static const char *ah_transtypestr[NUM_AH_TRANS_TYPES] = {
127   "RESERVED",
128   "RESERVED",
129   "MD5",
130   "SHA",
131   "DES",
132   "SHA2-256",
133   "SHA2-384",
134   "SHA2-512"
135 };
136
137 #define NUM_ESP_TRANS_TYPES     13
138 #define esp_trans2str(t)        \
139   ((t < NUM_ESP_TRANS_TYPES) ? esp_transtypestr[t] : "UNKNOWN-ESP-TRANS-TYPE")
140
141 static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
142   "RESERVED",
143   "DES-IV64",
144   "DES",
145   "3DES",
146   "RC5",
147   "IDEA",
148   "CAST",
149   "BLOWFISH",
150   "3IDEA",
151   "DES-IV32",
152   "RC4",
153   "NULL",
154   "AES"
155 };
156
157 #define NUM_ID_TYPES    12
158 #define id2str(t)       \
159   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
160
161 static const char *idtypestr[NUM_ID_TYPES] = {
162   "RESERVED",
163   "IPV4_ADDR",
164   "FQDN",
165   "USER_FQDN",
166   "IPV4_ADDR_SUBNET",
167   "IPV6_ADDR",
168   "IPV6_ADDR_SUBNET",
169   "IPV4_ADDR_RANGE",
170   "IPV6_ADDR_RANGE",
171   "DER_ASN1_DN",
172   "DER_ASN1_GN",
173   "KEY_ID"
174 };
175
176 struct isakmp_hdr {
177   guint8        icookie[8];
178   guint8        rcookie[8];
179   guint8        next_payload;
180   guint8        version;
181   guint8        exch_type;
182   guint8        flags;
183 #define E_FLAG          0x01
184 #define C_FLAG          0x02
185 #define A_FLAG          0x04
186   guint8        message_id[4];
187   guint8        length[4];
188 };
189
190 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
191     guint8 *, guint16 *, proto_tree *);
192
193 static void dissect_none(tvbuff_t *, int, int, proto_tree *);
194 static void dissect_sa(tvbuff_t *, int, int, proto_tree *);
195 static void dissect_proposal(tvbuff_t *, int, int, proto_tree *);
196 static void dissect_transform(tvbuff_t *, int, int, proto_tree *, guint8);
197 static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *);
198 static void dissect_id(tvbuff_t *, int, int, proto_tree *);
199 static void dissect_cert(tvbuff_t *, int, int, proto_tree *);
200 static void dissect_certreq(tvbuff_t *, int, int, proto_tree *);
201 static void dissect_hash(tvbuff_t *, int, int, proto_tree *);
202 static void dissect_sig(tvbuff_t *, int, int, proto_tree *);
203 static void dissect_nonce(tvbuff_t *, int, int, proto_tree *);
204 static void dissect_notif(tvbuff_t *, int, int, proto_tree *);
205 static void dissect_delete(tvbuff_t *, int, int, proto_tree *);
206 static void dissect_vid(tvbuff_t *, int, int, proto_tree *);
207 static void dissect_config(tvbuff_t *, int, int, proto_tree *);
208
209 static const char *payloadtype2str(guint8);
210 static const char *exchtype2str(guint8);
211 static const char *doitype2str(guint32);
212 static const char *msgtype2str(guint16);
213 static const char *situation2str(guint32);
214 static const char *value2str(int, guint16, guint16);
215 static const char *attrtype2str(guint8);
216 static const char *cfgattrident2str(guint16);
217 static const char *certtype2str(guint8);
218
219 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
220
221 #define LOAD_TYPE_PROPOSAL      2       /* payload type for Proposal */
222 #define LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
223 #define NUM_LOAD_TYPES          15
224 #define loadtype2str(t) \
225   ((t < NUM_LOAD_TYPES) ? strfuncs[t].str : "Unknown payload type")
226
227 static struct strfunc {
228   const char *  str;
229   void          (*func)(tvbuff_t *, int, int, proto_tree *);
230 } strfuncs[NUM_LOAD_TYPES] = {
231   {"NONE",                      dissect_none      },
232   {"Security Association",      dissect_sa        },
233   {"Proposal",                  dissect_proposal  },
234   {"Transform",                 NULL },
235   {"Key Exchange",              dissect_key_exch  },
236   {"Identification",            dissect_id        },
237   {"Certificate",               dissect_cert      },
238   {"Certificate Request",       dissect_certreq   },
239   {"Hash",                      dissect_hash      },
240   {"Signature",                 dissect_sig       },
241   {"Nonce",                     dissect_nonce     },
242   {"Notification",              dissect_notif     },
243   {"Delete",                    dissect_delete    },
244   {"Vendor ID",                 dissect_vid       },
245   {"Attrib",                    dissect_config    }
246 };
247
248 static void
249 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
250 {
251   int                   offset = 0;
252   struct isakmp_hdr *   hdr;
253   guint32               len;
254   guint8                payload, next_payload;
255   guint16               payload_length;
256   proto_tree *          ntree;
257
258   if (check_col(pinfo->fd, COL_PROTOCOL))
259     col_set_str(pinfo->fd, COL_PROTOCOL, "ISAKMP");
260   if (check_col(pinfo->fd, COL_INFO))
261     col_clear(pinfo->fd, COL_INFO);
262   
263   hdr = (struct isakmp_hdr *)tvb_get_ptr(tvb, 0, sizeof (struct isakmp_hdr));
264   len = pntohl(&hdr->length);
265   
266   if (check_col(pinfo->fd, COL_INFO))
267     col_add_str(pinfo->fd, COL_INFO, exchtype2str(hdr->exch_type));
268   
269   if (tree) {
270     proto_item *        ti;
271     proto_tree *        isakmp_tree;
272     
273     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, len, FALSE);
274     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
275     
276     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->icookie),
277                         "Initiator cookie");
278     offset += sizeof(hdr->icookie);
279     
280     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->rcookie),
281                         "Responder cookie");
282     offset += sizeof(hdr->rcookie);
283
284     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->next_payload),
285                         "Next payload: %s (%u)",
286                         payloadtype2str(hdr->next_payload), hdr->next_payload);
287     offset += sizeof(hdr->next_payload);
288
289     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->version),
290                         "Version: %u.%u",
291                         hi_nibble(hdr->version), lo_nibble(hdr->version));
292     offset += sizeof(hdr->version);
293     
294     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->exch_type),
295                         "Exchange type: %s (%u)",
296                         exchtype2str(hdr->exch_type), hdr->exch_type);
297     offset += sizeof(hdr->exch_type);
298     
299     {
300       proto_item *      fti;
301       proto_tree *      ftree;
302       
303       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->flags), "Flags");
304       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
305       
306       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
307                           decode_boolean_bitfield(hdr->flags, E_FLAG, sizeof(hdr->flags)*8,
308                                                   "Encryption", "No encryption"));
309       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
310                           decode_boolean_bitfield(hdr->flags, C_FLAG, sizeof(hdr->flags)*8,
311                                                   "Commit", "No commit"));
312       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
313                           decode_boolean_bitfield(hdr->flags, A_FLAG, sizeof(hdr->flags)*8,
314                                                   "Authentication", "No authentication"));
315       offset += sizeof(hdr->flags);
316     }
317
318     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->message_id),
319         "Message ID: 0x%02x%02x%02x%02x", hdr->message_id[0],
320         hdr->message_id[1], hdr->message_id[2], hdr->message_id[3]);
321     offset += sizeof(hdr->message_id);
322     
323     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->length),
324                         "Length: %u", len);
325     offset += sizeof(hdr->length);
326     len -= sizeof(*hdr);
327
328     if (hdr->flags & E_FLAG) {
329       if (len && isakmp_tree) {
330         proto_tree_add_text(isakmp_tree, tvb, offset, len,
331                         "Encrypted payload (%d byte%s)",
332                         len, plurality(len, "", "s"));
333       }
334     } else {
335       for (payload = hdr->next_payload; len != 0; payload = next_payload) {
336         ntree = dissect_payload_header(tvb, offset, len, payload,
337             &next_payload, &payload_length, isakmp_tree);
338         if (ntree == NULL)
339           break;
340         if (payload_length >= 4) {      /* XXX = > 4? */
341           if (payload < NUM_LOAD_TYPES) {
342             if (next_payload == LOAD_TYPE_TRANSFORM)
343               dissect_transform(tvb, offset + 4, payload_length - 4, ntree, 0);
344                 /* XXX - protocol ID? */
345             else
346               (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree);
347           }
348           else {
349             proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
350                 "Payload");
351           }
352         }
353         else {
354             proto_tree_add_text(ntree, tvb, offset + 4, 0,
355                 "Payload (bogus, length is %u, must be at least 4)",
356                 payload_length);
357             payload_length = 4;
358         }
359         offset += payload_length;
360         len -= payload_length;
361       }
362     }
363   }
364 }
365
366 static proto_tree *
367 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
368     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
369 {
370   guint8                next_payload;
371   guint16               payload_length;
372   proto_item *          ti;
373   proto_tree *          ntree;
374
375   if (length < 4) {
376     proto_tree_add_text(tree, tvb, offset, length,
377           "Not enough room in payload for all transforms");
378     return NULL;
379   }
380   next_payload = tvb_get_guint8(tvb, offset);
381   payload_length = tvb_get_ntohs(tvb, offset + 2);
382
383   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
384             "%s payload", loadtype2str(payload));
385   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
386
387   proto_tree_add_text(ntree, tvb, offset, 1,
388                       "Next payload: %s (%u)",
389                       payloadtype2str(next_payload), next_payload);
390   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
391
392   *next_payload_p = next_payload;
393   *payload_length_p = payload_length;
394   return ntree;
395 }
396
397 static void
398 dissect_none(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
399 {
400 }
401
402 static void
403 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
404 {
405   guint32               doi;
406   guint32               situation;
407   guint8                next_payload;
408   guint16               payload_length;
409   proto_tree *          ntree;
410
411   doi = tvb_get_ntohl(tvb, offset);
412   proto_tree_add_text(tree, tvb, offset, 4,
413                       "Domain of interpretation: %s (%u)",
414                       doitype2str(doi), doi);
415   offset += 4;
416   length -= 4;
417   
418   situation = tvb_get_ntohl(tvb, offset);
419   proto_tree_add_text(tree, tvb, offset, 4,
420                       "Situation: %s (%u)",
421                       situation2str(situation), situation);
422   offset += 4;
423   length -= 4;
424   
425   ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_PROPOSAL,
426     &next_payload, &payload_length, tree);
427   if (ntree != NULL)
428     dissect_proposal(tvb, offset + 4, payload_length - 4, ntree);
429 }
430
431 static void
432 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
433 {
434   guint8                protocol_id;
435   guint8                spi_size;
436   guint8                num_transforms;
437   guint8                next_payload;
438   guint16               payload_length;
439   proto_tree *          ntree;
440
441   proto_tree_add_text(tree, tvb, offset, 1,
442                       "Proposal number: %u", tvb_get_guint8(tvb, offset));
443   offset += 1;
444   length -= 1;
445   
446   protocol_id = tvb_get_guint8(tvb, offset);
447   proto_tree_add_text(tree, tvb, offset, 1,
448                       "Protocol ID: %s (%u)",
449                       proto2str(protocol_id), protocol_id);
450   offset += 1;
451   length -= 1;
452   
453   spi_size = tvb_get_guint8(tvb, offset);
454   proto_tree_add_text(tree, tvb, offset, 1,
455                       "SPI size: %u", spi_size);
456   offset += 1;
457   length -= 1;
458
459   num_transforms = tvb_get_guint8(tvb, offset);
460   proto_tree_add_text(tree, tvb, offset, 1,
461                       "Number of transforms: %u", num_transforms);
462   offset += 1;
463   length -= 1;
464
465   if (spi_size) {
466     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI");
467     offset += spi_size;
468     length -= spi_size;
469   }
470
471   while (num_transforms > 0) {
472     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
473       &next_payload, &payload_length, tree);
474     if (ntree == NULL)
475       break;
476     if (length < payload_length) {
477       proto_tree_add_text(tree, tvb, offset + 4, length,
478           "Not enough room in payload for all transforms");
479       break;
480     }
481     if (payload_length >= 4)
482       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
483     else
484       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
485     offset += payload_length;
486     length -= payload_length;
487     num_transforms--;
488   }
489 }
490
491 static void
492 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
493     guint8 protocol_id)
494 {
495   guint8                transform_id;
496
497   proto_tree_add_text(tree, tvb, offset, 1,
498                       "Transform number: %u", tvb_get_guint8(tvb, offset));
499   offset += 1;
500   length -= 1;
501
502   transform_id = tvb_get_guint8(tvb, offset);
503   switch (protocol_id) {
504   default:
505   case 1:       /* ISAKMP */
506     proto_tree_add_text(tree, tvb, offset, 1,
507                         "Transform ID: %s (%u)",
508                         trans2str(transform_id), transform_id);
509     break;
510   case 2:       /* AH */
511     proto_tree_add_text(tree, tvb, offset, 1,
512                         "Transform ID: %s (%u)",
513                         ah_trans2str(transform_id), transform_id);
514     break;
515   case 3:       /* ESP */
516     proto_tree_add_text(tree, tvb, offset, 1,
517                         "Transform ID: %s (%u)",
518                         esp_trans2str(transform_id), transform_id);
519     break;
520   }
521   offset += 3;
522   length -= 3;
523   
524   while (length>0) {
525     const char *str;
526     int ike_phase1 = 0;
527     guint16 aft     = tvb_get_ntohs(tvb, offset);
528     guint16 type    = aft & 0x7fff;
529     guint16 len;
530     guint32 val;
531     guint pack_len;
532
533     if (protocol_id == 1 && transform_id == 1) {
534       ike_phase1 = 1;
535       str = p1_atttype2str(type);
536     }
537     else {
538       str = atttype2str(type);
539     }
540
541     if (aft & 0x8000) {
542       val = tvb_get_ntohs(tvb, offset + 2);
543       proto_tree_add_text(tree, tvb, offset, 4,
544                           "%s (%u): %s (%u)",
545                           str, type,
546                           value2str(ike_phase1, type, val), val);
547       offset += 4;
548       length -= 4;
549     }
550     else {
551       len = tvb_get_ntohs(tvb, offset + 2);
552       pack_len = 4 + len;
553       if (!get_num(tvb, offset + 4, len, &val)) {
554         proto_tree_add_text(tree, tvb, offset, pack_len,
555                             "%s (%u): <too big (%u bytes)>",
556                             str, type, len);
557       } else {
558         proto_tree_add_text(tree, tvb, offset, pack_len,
559                             "%s (%u): %s (%u)",
560                             str, type,
561                             value2str(ike_phase1, type, val), val);
562       }
563       offset += pack_len;
564       length -= pack_len;
565     }
566   }
567 }
568
569 static void
570 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
571 {
572   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
573 }
574
575 static void
576 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
577 {
578   guint8                id_type;
579   guint8                protocol_id;
580   guint16               port;
581
582   id_type = tvb_get_guint8(tvb, offset);
583   proto_tree_add_text(tree, tvb, offset, 1,
584                       "ID type: %s (%u)", id2str(id_type), id_type);
585   offset += 1;
586   length -= 1;
587
588   protocol_id = tvb_get_guint8(tvb, offset);
589   if (protocol_id == 0) {
590     proto_tree_add_text(tree, tvb, offset, 1,
591                         "Protocol ID: Unused");
592   } else {
593     proto_tree_add_text(tree, tvb, offset, 1,
594                         "Protocol ID: %s (%u)",
595                         ipprotostr(protocol_id), protocol_id);
596   }
597   offset += 1;
598   length -= 1;
599
600   port = tvb_get_ntohs(tvb, offset);
601   if (port == 0)
602     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
603   else
604     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
605   offset += 2;
606   length -= 2;
607   
608   switch (id_type) {
609     case 1:
610     case 4:
611       proto_tree_add_text(tree, tvb, offset, length,
612                           "Identification data: %s",
613                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
614       break;
615     case 2:
616     case 3:
617       proto_tree_add_text(tree, tvb, offset, length,
618                           "Identification data: %.*s", length,
619                           tvb_get_ptr(tvb, offset, length));
620       break;
621     default:
622       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
623       break;
624   }
625 }
626
627 static void
628 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
629 {
630   guint8                cert_enc;
631
632   cert_enc = tvb_get_guint8(tvb, offset);
633   proto_tree_add_text(tree, tvb, offset, 1,
634                       "Certificate encoding: %u - %s",
635                       cert_enc, certtype2str(cert_enc));
636   offset += 1;
637   length -= 1;
638
639   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
640 }
641
642 static void
643 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
644 {
645   guint8                cert_type;
646
647   cert_type = tvb_get_guint8(tvb, offset);
648   proto_tree_add_text(tree, tvb, offset, 1,
649                       "Certificate type: %u - %s",
650                       cert_type, certtype2str(cert_type));
651   offset += 1;
652   length -= 1;
653
654   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
655 }
656
657 static void
658 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
659 {
660   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
661 }
662
663 static void
664 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
665 {
666   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
667 }
668
669 static void
670 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
671 {
672   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
673 }
674
675 static void
676 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
677 {
678   guint32               doi;
679   guint8                protocol_id;
680   guint8                spi_size;
681   guint16               msgtype;
682
683   doi = tvb_get_ntohl(tvb, offset);
684   proto_tree_add_text(tree, tvb, offset, 4,
685                       "Domain of Interpretation: %s (%u)",
686                       doitype2str(doi), doi);
687   offset += 4;
688   length -= 4;
689
690   protocol_id = tvb_get_guint8(tvb, offset);
691   proto_tree_add_text(tree, tvb, offset, 1,
692                       "Protocol ID: %s (%u)",
693                       proto2str(protocol_id), protocol_id);
694   offset += 1;
695   length -= 1;
696   
697   spi_size = tvb_get_guint8(tvb, offset);
698   proto_tree_add_text(tree, tvb, offset, 1,
699                       "SPI size: %u", spi_size);
700   offset += 1;
701   length -= 1;
702   
703   msgtype = tvb_get_ntohs(tvb, offset);
704   proto_tree_add_text(tree, tvb, offset, 2,
705                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
706   offset += 2;
707   length -= 2;
708
709   if (spi_size) {
710     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
711     offset += spi_size;
712     length -= spi_size;
713   }
714
715   if (length > 0)
716     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
717 }
718
719 static void
720 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
721 {
722   guint32               doi;
723   guint8                protocol_id;
724   guint8                spi_size;
725   guint16               num_spis;
726   guint16               i;
727   
728   doi = tvb_get_ntohl(tvb, offset);
729   proto_tree_add_text(tree, tvb, offset, 4,
730                       "Domain of Interpretation: %s (%u)",
731                       doitype2str(doi), doi);
732   offset += 4;
733   length -= 4;
734
735   protocol_id = tvb_get_guint8(tvb, offset);
736   proto_tree_add_text(tree, tvb, offset, 1,
737                       "Protocol ID: %s (%u)",
738                       proto2str(protocol_id), protocol_id);
739   offset += 1;
740   length -= 1;
741   
742   spi_size = tvb_get_guint8(tvb, offset);
743   proto_tree_add_text(tree, tvb, offset, 1,
744                       "SPI size: %u", spi_size);
745   offset += 1;
746   length -= 1;
747
748   num_spis = tvb_get_ntohs(tvb, offset);
749   proto_tree_add_text(tree, tvb, offset, 2,
750                       "Number of SPIs: %u", num_spis);
751   offset += 2;
752   length -= 2;
753   
754   for (i = 0; i < num_spis; ++i) {
755     if (length < spi_size) {
756       proto_tree_add_text(tree, tvb, offset, length,
757           "Not enough room in payload for all SPI's");
758       break;
759     }
760     proto_tree_add_text(tree, tvb, offset, spi_size,
761                         "SPI (%d)", i);
762     offset += spi_size;
763     length -= spi_size;
764   }
765 }
766
767 static void
768 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
769 {
770   proto_tree_add_text(tree, tvb, offset, length, "Vendor ID");
771 }
772
773 static void
774 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
775 {
776   guint8                type;
777
778   type = tvb_get_guint8(tvb, offset);
779   proto_tree_add_text(tree, tvb, offset, 1,
780                       "Type %s (%u)",attrtype2str(type),type);
781   
782   offset += 2;
783   length -= 2;
784   
785   proto_tree_add_text(tree, tvb, offset, 2,
786                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
787   offset += 2;
788   length -= 2;
789   
790   while(length>0) {
791     guint16 aft     = tvb_get_ntohs(tvb, offset);
792     guint16 type    = aft & 0x7fff;
793     guint16 len;
794     guint32 val;
795     guint pack_len;
796
797     if (aft & 0x8000) {
798       val = tvb_get_ntohs(tvb, offset + 2);
799       proto_tree_add_text(tree, tvb, offset, 4,
800                           "%s (%u)", cfgattrident2str(type), val);
801       offset += 4;
802       length -= 4;
803     }
804     else {
805       len = tvb_get_ntohs(tvb, offset + 2);
806       pack_len = 4 + len;
807       if (!get_num(tvb, offset + 4, len, &val)) {
808         proto_tree_add_text(tree, tvb, offset, pack_len,
809                             "%s: <too big (%u bytes)>",
810                             cfgattrident2str(type), len);
811       } else {
812         proto_tree_add_text(tree, tvb, offset, 4,
813                             "%s (%ue)", cfgattrident2str(type),
814                             val);
815       }
816       offset += pack_len;
817       length -= pack_len;
818     }
819   }
820 }
821
822 static const char *
823 payloadtype2str(guint8 type) {
824
825   if (type < NUM_LOAD_TYPES) return strfuncs[type].str;
826   if (type < 128)            return "RESERVED";
827   if (type < 256)            return "Private USE";
828
829   return "Huh? You should never see this! Shame on you!";
830 }
831
832 static const char *
833 exchtype2str(guint8 type) {
834
835 #define NUM_EXCHSTRS    7
836   static const char * exchstrs[NUM_EXCHSTRS] = {
837     "NONE",
838     "Base",
839     "Identity Protection (Main Mode)",
840     "Authentication Only",
841     "Aggressive",
842     "Informational",
843     "Transaction (Config Mode)"
844   };
845   
846   if (type < NUM_EXCHSTRS) return exchstrs[type];
847   if (type < 32)           return "ISAKMP Future Use";
848   switch (type) {
849   case 32:
850     return "Quick Mode";
851   case 33:
852     return "New Group Mode";
853   }
854   if (type < 240)          return "DOI Specific Use";
855   if (type < 256)          return "Private Use";
856   
857   return "Huh? You should never see this! Shame on you!";
858 }
859
860 static const char *
861 doitype2str(guint32 type) {
862   if (type == 1) return "IPSEC";
863   return "Unknown DOI Type";
864 }
865
866 static const char *
867 msgtype2str(guint16 type) {
868
869 #define NUM_PREDEFINED  31
870   static const char *msgs[NUM_PREDEFINED] = {
871     "<UNKNOWN>",
872     "INVALID-PAYLOAD-TYPE",
873     "DOI-NOT-SUPPORTED",
874     "SITUATION-NOT-SUPPORTED",
875     "INVALID-COOKIE",
876     "INVALID-MAJOR-VERSION",
877     "INVALID-MINOR-VERSION",
878     "INVALID-EXCHANGE-TYPE",
879     "INVALID-FLAGS",
880     "INVALID-MESSAGE-ID",
881     "INVALID-PROTOCOL-ID",
882     "INVALID-SPI",
883     "INVALID-TRANSFORM-ID",
884     "ATTRIBUTES-NOT-SUPPORTED",
885     "NO-PROPOSAL-CHOSEN",
886     "BAD-PROPOSAL-SYNTAX",
887     "PAYLOAD-MALFORMED",
888     "INVALID-KEY-INFORMATION",
889     "INVALID-ID-INFORMATION",
890     "INVALID-CERT-ENCODING",
891     "INVALID-CERTIFICATE",
892     "CERT-TYPE-UNSUPPORTED",
893     "INVALID-CERT-AUTHORITY",
894     "INVALID-HASH-INFORMATION",
895     "AUTHENTICATION-FAILED",
896     "INVALID-SIGNATURE",
897     "ADDRESS-NOTIFICATION",
898     "NOTIFY-SA-LIFETIME",
899     "CERTIFICATE-UNAVAILABLE",
900     "UNSUPPORTED-EXCHANGE-TYPE",
901     "UNEQUAL-PAYLOAD-LENGTHS"
902   };
903
904   if (type < NUM_PREDEFINED) return msgs[type];
905   if (type < 8192)           return "RESERVED (Future Use)";
906   if (type < 16384)          return "Private Use";
907   if (type < 16385)          return "CONNECTED";
908   if (type < 24576)          return "RESERVED (Future Use) - status";
909   if (type < 24577)          return "RESPONDER-LIFETIME";
910   if (type < 24578)          return "REPLAY-STATUS";
911   if (type < 24579)          return "INITIAL-CONTACT";
912   if (type < 32768)          return "DOI-specific codes";
913   if (type < 40960)          return "Private Use - status";
914   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
915
916   return "Huh? You should never see this! Shame on you!";
917 }
918
919 static const char *
920 situation2str(guint32 type) {
921
922 #define SIT_MSG_NUM     1024
923 #define SIT_IDENTITY    0x01
924 #define SIT_SECRECY     0x02
925 #define SIT_INTEGRITY   0x04
926
927   static char   msg[SIT_MSG_NUM];
928   int           n = 0;
929   char *        sep = "";
930   
931   if (type & SIT_IDENTITY) {
932     n += snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
933     sep = " & ";
934   }
935   if (type & SIT_SECRECY) {
936     n += snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
937     sep = " & ";
938   }
939   if (type & SIT_INTEGRITY) {
940     n += snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
941     sep = " & ";
942   }
943
944   return msg;
945 }
946
947 static const char *
948 value2str(int ike_p1, guint16 att_type, guint16 value) {
949   
950   if (value == 0) return "RESERVED";
951   
952   if (!ike_p1) {
953   switch (att_type) {
954     case 1:
955       switch (value) {
956         case 1:  return "Seconds";
957         case 2:  return "Kilobytes";
958         default: return "UNKNOWN-SA-VALUE";
959       }
960     case 2:
961       return "Duration-Value";
962     case 3:
963       return "Group-Value";
964     case 4:
965       switch (value) {
966         case 1:  return "Tunnel";
967         case 2:  return "Transport";
968         default: return "UNKNOWN-ENCAPSULATION-VALUE";
969       }
970     case 5:
971       switch (value) {
972         case 1:  return "HMAC-MD5";
973         case 2:  return "HMAC-SHA";
974         case 3:  return "DES-MAC";
975         case 4:  return "KPDK";
976         case 5:  return "HMAC-SHA2-256";
977         case 6:  return "HMAC-SHA2-384";
978         case 7:  return "HMAC-SHA2-512";
979         default: return "UNKNOWN-AUTHENTICATION-VALUE";
980       }
981     case 6:
982       return "Key-Length";
983     case 7:
984       return "Key-Rounds";
985     case 8:
986       return "log2-size";
987     default: return "UNKNOWN-ATTRIBUTE-TYPE";
988   }
989   }
990   else {
991     switch (att_type) {
992       case 1:
993         switch (value) {
994           case 1:  return "DES-CBC";
995           case 2:  return "IDEA-CBC";
996           case 3:  return "BLOWFISH-CBC";
997           case 4:  return "RC5-R16-B64-CBC";
998           case 5:  return "3DES-CBC";
999           case 6:  return "CAST-CBC";
1000           case 7:  return "AES-CBC";
1001           default: return "UNKNOWN-ENCRYPTION-ALG";
1002         }
1003       case 2:
1004         switch (value) {
1005           case 1:  return "MD5";
1006           case 2:  return "SHA";
1007           case 3:  return "TIGER";
1008           case 4:  return "SHA2-256";
1009           case 5:  return "SHA2-384";
1010           case 6:  return "SHA2-512";
1011           default: return "UNKNOWN-HASH-ALG";
1012         }
1013       case 3:
1014         switch (value) {
1015           case 1:  return "PSK";
1016           case 2:  return "DSS-SIG";
1017           case 3:  return "RSA-SIG";
1018           case 4:  return "RSA-ENC";
1019           case 5:  return "RSA-Revised-ENC";
1020           case 64221: return "HybridInitRSA";
1021           case 64222: return "HybridRespRSA";
1022           case 64223: return "HybridInitDSS";
1023           case 64224: return "HybridRespDSS";
1024           case 65001: return "XAUTHInitPreShared";
1025           case 65002: return "XAUTHRespPreShared";
1026           case 65003: return "XAUTHInitDSS";
1027           case 65004: return "XAUTHRespDSS";
1028           case 65005: return "XAUTHInitRSA";
1029           case 65006: return "XAUTHRespRSA";
1030           case 65007: return "XAUTHInitRSAEncryption";
1031           case 65008: return "XAUTHRespRSAEncryption";
1032           case 65009: return "XAUTHInitRSARevisedEncryption";
1033           case 65010: return "XAUTHRespRSARevisedEncryption";
1034           default: return "UNKNOWN-AUTH-METHOD";
1035         }
1036       case 4:
1037       case 6:
1038       case 7:
1039       case 8:
1040       case 9:
1041       case 10:
1042       case 16:
1043         return "Group-Value";
1044       case 5:
1045         switch (value) {
1046           case 1:  return "MODP";
1047           case 2:  return "ECP";
1048           case 3:  return "EC2N";
1049           default: return "UNKNOWN-GROUPT-TYPE";
1050         }
1051       case 11:
1052         switch (value) {
1053           case 1:  return "Seconds";
1054           case 2:  return "Kilobytes";
1055           default: return "UNKNOWN-SA-VALUE";
1056         }
1057       case 12:
1058         return "Duration-Value";
1059       case 13:
1060         return "PRF-Value";
1061       case 14:
1062         return "Key-Length";
1063       case 15:
1064         return "Field-Size";
1065       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1066     }
1067   }
1068 }
1069
1070 static const char * 
1071 attrtype2str(guint8 type) {
1072   switch (type) {
1073   case 0: return "Reserved";
1074   case 1: return "ISAKMP_CFG_REQUEST";
1075   case 2: return "ISAKMP_CFG_REPLY";
1076   case 3: return "ISAKMP_CFG_SET";
1077   case 4: return "ISAKMP_CFG_ACK";
1078   }
1079   if(type < 127)
1080     return "Future use";
1081   return "Private use";
1082 }
1083
1084 static const char * 
1085 cfgattrident2str(guint16 ident) {
1086 #define NUM_ATTR_DEFINED        12
1087   static const char *msgs[NUM_PREDEFINED] = {
1088     "RESERVED",
1089     "INTERNAL_IP4_ADDRESS",
1090     "INTERNAL_IP4_NETMASK",
1091     "INTERNAL_IP4_DNS",
1092     "INTERNAL_IP4_NBNS",
1093     "INTERNAL_ADDRESS_EXPIREY",
1094     "INTERNAL_IP4_DHCP",
1095     "APPLICATION_VERSION"
1096     "INTERNAL_IP6_ADDRESS",
1097     "INTERNAL_IP6_NETMASK",
1098     "INTERNAL_IP6_DNS",
1099     "INTERNAL_IP6_NBNS",
1100     "INTERNAL_IP6_DHCP",
1101   }; 
1102   if(ident < NUM_ATTR_DEFINED)
1103     return msgs[ident];
1104   if(ident < 16383)
1105     return "Future use";
1106   switch(ident) {
1107   case 16520: return "XAUTH_TYPE";
1108   case 16521: return "XAUTH_USER_NAME";
1109   case 16522: return "XAUTH_USER_PASSWORD";
1110   case 16523: return "XAUTH_PASSCODE";
1111   case 16524: return "XAUTH_MESSAGE";
1112   case 16525: return "XAUTH_CHALLANGE";
1113   case 16526: return "XAUTH_DOMAIN";
1114   case 16527: return "XAUTH_STATUS";
1115   default: return "Private use";
1116   }
1117 }
1118
1119 static const char *
1120 certtype2str(guint8 type) {
1121 #define NUM_CERTTYPE 11
1122   static const char *msgs[NUM_CERTTYPE] = {
1123     "NONE",
1124     "PKCS #7 wrapped X.509 certificate",
1125     "PGP Certificate",
1126     "DNS Signed Key",
1127     "X.509 Certificate - Signature",
1128     "X.509 Certificate - Key Exchange",
1129     "Kerberos Tokens",
1130     "Certificate Revocation List (CRL)",
1131     "Authority Revocation List (ARL)",
1132     "SPKI Certificate",
1133     "X.509 Certificate - Attribute",
1134   };
1135   if(type > NUM_CERTTYPE)
1136     return "RESERVED";
1137   return msgs[type];
1138 }
1139
1140 static gboolean
1141 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1142
1143   switch (len) {
1144   case 1:
1145     *num_p = tvb_get_guint8(tvb, offset);
1146     break;
1147   case 2:
1148     *num_p = tvb_get_ntohs(tvb, offset);
1149     break;
1150   case 3:
1151     *num_p = tvb_get_ntoh24(tvb, offset);
1152     break;
1153   case 4:
1154     *num_p = tvb_get_ntohl(tvb, offset);
1155     break;
1156   default:
1157     return FALSE;
1158   }
1159
1160   return TRUE;
1161 }
1162
1163 void
1164 proto_register_isakmp(void)
1165 {
1166 /*  static hf_register_info hf[] = {
1167     { &variable,
1168     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1169   };*/
1170   static gint *ett[] = {
1171     &ett_isakmp,
1172     &ett_isakmp_flags,
1173     &ett_isakmp_payload,
1174   };
1175
1176   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1177                                                "ISAKMP", "isakmp");
1178 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1179   proto_register_subtree_array(ett, array_length(ett));
1180 }
1181
1182 void
1183 proto_reg_handoff_isakmp(void)
1184 {
1185   dissector_add("udp.port", UDP_PORT_ISAKMP, dissect_isakmp, proto_isakmp);
1186 }